123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- package internal
- import (
- "errors"
- "sort"
- "strconv"
- "testing"
- "zero/core/logx"
- "zero/core/mathx"
- "github.com/golang/mock/gomock"
- "github.com/stretchr/testify/assert"
- )
- func init() {
- logx.Disable()
- }
- func TestRoundRobin_addConn(t *testing.T) {
- b := NewRoundRobinBalancer(func(server string) (interface{}, error) {
- return mockConn{
- server: server,
- }, nil
- }, func(server string, conn interface{}) error {
- return errors.New("error")
- }, false)
- assert.Nil(t, b.AddConn(KV{
- Key: "thekey1",
- Val: "thevalue",
- }))
- assert.EqualValues(t, []serverConn{
- {
- key: "thekey1",
- conn: mockConn{server: "thevalue"},
- },
- }, b.conns)
- assert.EqualValues(t, map[string][]string{
- "thevalue": {"thekey1"},
- }, b.servers)
- assert.EqualValues(t, map[string]string{
- "thekey1": "thevalue",
- }, b.mapping)
- assert.Nil(t, b.AddConn(KV{
- Key: "thekey2",
- Val: "thevalue",
- }))
- assert.EqualValues(t, []serverConn{
- {
- key: "thekey1",
- conn: mockConn{server: "thevalue"},
- },
- {
- key: "thekey2",
- conn: mockConn{server: "thevalue"},
- },
- }, b.conns)
- assert.EqualValues(t, map[string][]string{
- "thevalue": {"thekey1", "thekey2"},
- }, b.servers)
- assert.EqualValues(t, map[string]string{
- "thekey1": "thevalue",
- "thekey2": "thevalue",
- }, b.mapping)
- assert.False(t, b.IsEmpty())
- b.RemoveKey("thekey1")
- assert.EqualValues(t, []serverConn{
- {
- key: "thekey2",
- conn: mockConn{server: "thevalue"},
- },
- }, b.conns)
- assert.EqualValues(t, map[string][]string{
- "thevalue": {"thekey2"},
- }, b.servers)
- assert.EqualValues(t, map[string]string{
- "thekey2": "thevalue",
- }, b.mapping)
- assert.False(t, b.IsEmpty())
- b.RemoveKey("thekey2")
- assert.EqualValues(t, []serverConn{}, b.conns)
- assert.EqualValues(t, map[string][]string{}, b.servers)
- assert.EqualValues(t, map[string]string{}, b.mapping)
- assert.True(t, b.IsEmpty())
- }
- func TestRoundRobin_addConnExclusive(t *testing.T) {
- b := NewRoundRobinBalancer(func(server string) (interface{}, error) {
- return mockConn{
- server: server,
- }, nil
- }, func(server string, conn interface{}) error {
- return nil
- }, true)
- assert.Nil(t, b.AddConn(KV{
- Key: "thekey1",
- Val: "thevalue",
- }))
- assert.EqualValues(t, []serverConn{
- {
- key: "thekey1",
- conn: mockConn{server: "thevalue"},
- },
- }, b.conns)
- assert.EqualValues(t, map[string][]string{
- "thevalue": {"thekey1"},
- }, b.servers)
- assert.EqualValues(t, map[string]string{
- "thekey1": "thevalue",
- }, b.mapping)
- assert.Nil(t, b.AddConn(KV{
- Key: "thekey2",
- Val: "thevalue",
- }))
- assert.EqualValues(t, []serverConn{
- {
- key: "thekey2",
- conn: mockConn{server: "thevalue"},
- },
- }, b.conns)
- assert.EqualValues(t, map[string][]string{
- "thevalue": {"thekey2"},
- }, b.servers)
- assert.EqualValues(t, map[string]string{
- "thekey2": "thevalue",
- }, b.mapping)
- assert.False(t, b.IsEmpty())
- b.RemoveKey("thekey1")
- b.RemoveKey("thekey2")
- assert.EqualValues(t, []serverConn{}, b.conns)
- assert.EqualValues(t, map[string][]string{}, b.servers)
- assert.EqualValues(t, map[string]string{}, b.mapping)
- assert.True(t, b.IsEmpty())
- }
- func TestRoundRobin_addConnDupExclusive(t *testing.T) {
- b := NewRoundRobinBalancer(func(server string) (interface{}, error) {
- return mockConn{
- server: server,
- }, nil
- }, func(server string, conn interface{}) error {
- return errors.New("error")
- }, true)
- assert.Nil(t, b.AddConn(KV{
- Key: "thekey1",
- Val: "thevalue",
- }))
- assert.EqualValues(t, []serverConn{
- {
- key: "thekey1",
- conn: mockConn{server: "thevalue"},
- },
- }, b.conns)
- assert.EqualValues(t, map[string][]string{
- "thevalue": {"thekey1"},
- }, b.servers)
- assert.EqualValues(t, map[string]string{
- "thekey1": "thevalue",
- }, b.mapping)
- assert.Nil(t, b.AddConn(KV{
- Key: "thekey",
- Val: "anothervalue",
- }))
- assert.Nil(t, b.AddConn(KV{
- Key: "thekey1",
- Val: "thevalue",
- }))
- assert.EqualValues(t, []serverConn{
- {
- key: "thekey",
- conn: mockConn{server: "anothervalue"},
- },
- {
- key: "thekey1",
- conn: mockConn{server: "thevalue"},
- },
- }, b.conns)
- assert.EqualValues(t, map[string][]string{
- "anothervalue": {"thekey"},
- "thevalue": {"thekey1"},
- }, b.servers)
- assert.EqualValues(t, map[string]string{
- "thekey": "anothervalue",
- "thekey1": "thevalue",
- }, b.mapping)
- assert.False(t, b.IsEmpty())
- b.RemoveKey("thekey")
- b.RemoveKey("thekey1")
- assert.EqualValues(t, []serverConn{}, b.conns)
- assert.EqualValues(t, map[string][]string{}, b.servers)
- assert.EqualValues(t, map[string]string{}, b.mapping)
- assert.True(t, b.IsEmpty())
- }
- func TestRoundRobin_addConnError(t *testing.T) {
- b := NewRoundRobinBalancer(func(server string) (interface{}, error) {
- return nil, errors.New("error")
- }, func(server string, conn interface{}) error {
- return nil
- }, true)
- assert.NotNil(t, b.AddConn(KV{
- Key: "thekey1",
- Val: "thevalue",
- }))
- assert.Nil(t, b.conns)
- assert.EqualValues(t, map[string][]string{}, b.servers)
- assert.EqualValues(t, map[string]string{}, b.mapping)
- }
- func TestRoundRobin_initialize(t *testing.T) {
- b := NewRoundRobinBalancer(func(server string) (interface{}, error) {
- return mockConn{
- server: server,
- }, nil
- }, func(server string, conn interface{}) error {
- return nil
- }, true)
- for i := 0; i < 100; i++ {
- assert.Nil(t, b.AddConn(KV{
- Key: "thekey/" + strconv.Itoa(i),
- Val: "thevalue/" + strconv.Itoa(i),
- }))
- }
- m := make(map[int]int)
- const total = 1000
- for i := 0; i < total; i++ {
- b.initialize()
- m[b.index]++
- }
- mi := make(map[interface{}]int, len(m))
- for k, v := range m {
- mi[k] = v
- }
- entropy := mathx.CalcEntropy(mi, total)
- assert.True(t, entropy > .95)
- }
- func TestRoundRobin_next(t *testing.T) {
- b := NewRoundRobinBalancer(func(server string) (interface{}, error) {
- return mockConn{
- server: server,
- }, nil
- }, func(server string, conn interface{}) error {
- return errors.New("error")
- }, true)
- const size = 100
- for i := 0; i < size; i++ {
- assert.Nil(t, b.AddConn(KV{
- Key: "thekey/" + strconv.Itoa(i),
- Val: "thevalue/" + strconv.Itoa(i),
- }))
- }
- m := make(map[interface{}]int)
- const total = 10000
- for i := 0; i < total; i++ {
- val, ok := b.Next()
- assert.True(t, ok)
- m[val]++
- }
- entropy := mathx.CalcEntropy(m, total)
- assert.Equal(t, size, len(m))
- assert.True(t, entropy > .95)
- for i := 0; i < size; i++ {
- b.RemoveKey("thekey/" + strconv.Itoa(i))
- }
- _, ok := b.Next()
- assert.False(t, ok)
- }
- func TestRoundRobinBalancer_Listener(t *testing.T) {
- ctrl := gomock.NewController(t)
- defer ctrl.Finish()
- b := NewRoundRobinBalancer(func(server string) (interface{}, error) {
- return mockConn{
- server: server,
- }, nil
- }, func(server string, conn interface{}) error {
- return nil
- }, true)
- assert.Nil(t, b.AddConn(KV{
- Key: "key1",
- Val: "val1",
- }))
- assert.Nil(t, b.AddConn(KV{
- Key: "key2",
- Val: "val2",
- }))
- listener := NewMockListener(ctrl)
- listener.EXPECT().OnUpdate(gomock.Any(), gomock.Any(), "key2").Do(func(keys, vals, _ interface{}) {
- sort.Strings(vals.([]string))
- sort.Strings(keys.([]string))
- assert.EqualValues(t, []string{"key1", "key2"}, keys)
- assert.EqualValues(t, []string{"val1", "val2"}, vals)
- })
- b.setListener(listener)
- b.notify("key2")
- }
- func TestRoundRobinBalancer_remove(t *testing.T) {
- b := NewRoundRobinBalancer(func(server string) (interface{}, error) {
- return mockConn{
- server: server,
- }, nil
- }, func(server string, conn interface{}) error {
- return nil
- }, true)
- assert.Nil(t, b.handlePrevious(nil, "any"))
- _, ok := b.doRemoveKv("any")
- assert.True(t, ok)
- }
|