github.com/lingyao2333/mo-zero@v1.4.1/core/discov/internal/registry_test.go (about) 1 package internal 2 3 import ( 4 "context" 5 "sync" 6 "testing" 7 8 "github.com/golang/mock/gomock" 9 "github.com/lingyao2333/mo-zero/core/contextx" 10 "github.com/lingyao2333/mo-zero/core/lang" 11 "github.com/lingyao2333/mo-zero/core/logx" 12 "github.com/lingyao2333/mo-zero/core/stringx" 13 "github.com/stretchr/testify/assert" 14 "go.etcd.io/etcd/api/v3/etcdserverpb" 15 "go.etcd.io/etcd/api/v3/mvccpb" 16 clientv3 "go.etcd.io/etcd/client/v3" 17 ) 18 19 var mockLock sync.Mutex 20 21 func init() { 22 logx.Disable() 23 } 24 25 func setMockClient(cli EtcdClient) func() { 26 mockLock.Lock() 27 NewClient = func([]string) (EtcdClient, error) { 28 return cli, nil 29 } 30 return func() { 31 NewClient = DialClient 32 mockLock.Unlock() 33 } 34 } 35 36 func TestGetCluster(t *testing.T) { 37 AddAccount([]string{"first"}, "foo", "bar") 38 c1, _ := GetRegistry().getCluster([]string{"first"}) 39 c2, _ := GetRegistry().getCluster([]string{"second"}) 40 c3, _ := GetRegistry().getCluster([]string{"first"}) 41 assert.Equal(t, c1, c3) 42 assert.NotEqual(t, c1, c2) 43 } 44 45 func TestGetClusterKey(t *testing.T) { 46 assert.Equal(t, getClusterKey([]string{"localhost:1234", "remotehost:5678"}), 47 getClusterKey([]string{"remotehost:5678", "localhost:1234"})) 48 } 49 50 func TestCluster_HandleChanges(t *testing.T) { 51 ctrl := gomock.NewController(t) 52 l := NewMockUpdateListener(ctrl) 53 l.EXPECT().OnAdd(KV{ 54 Key: "first", 55 Val: "1", 56 }) 57 l.EXPECT().OnAdd(KV{ 58 Key: "second", 59 Val: "2", 60 }) 61 l.EXPECT().OnDelete(KV{ 62 Key: "first", 63 Val: "1", 64 }) 65 l.EXPECT().OnDelete(KV{ 66 Key: "second", 67 Val: "2", 68 }) 69 l.EXPECT().OnAdd(KV{ 70 Key: "third", 71 Val: "3", 72 }) 73 l.EXPECT().OnAdd(KV{ 74 Key: "fourth", 75 Val: "4", 76 }) 77 c := newCluster([]string{"any"}) 78 c.listeners["any"] = []UpdateListener{l} 79 c.handleChanges("any", []KV{ 80 { 81 Key: "first", 82 Val: "1", 83 }, 84 { 85 Key: "second", 86 Val: "2", 87 }, 88 }) 89 assert.EqualValues(t, map[string]string{ 90 "first": "1", 91 "second": "2", 92 }, c.values["any"]) 93 c.handleChanges("any", []KV{ 94 { 95 Key: "third", 96 Val: "3", 97 }, 98 { 99 Key: "fourth", 100 Val: "4", 101 }, 102 }) 103 assert.EqualValues(t, map[string]string{ 104 "third": "3", 105 "fourth": "4", 106 }, c.values["any"]) 107 } 108 109 func TestCluster_Load(t *testing.T) { 110 ctrl := gomock.NewController(t) 111 defer ctrl.Finish() 112 cli := NewMockEtcdClient(ctrl) 113 restore := setMockClient(cli) 114 defer restore() 115 cli.EXPECT().Get(gomock.Any(), "any/", gomock.Any()).Return(&clientv3.GetResponse{ 116 Header: &etcdserverpb.ResponseHeader{}, 117 Kvs: []*mvccpb.KeyValue{ 118 { 119 Key: []byte("hello"), 120 Value: []byte("world"), 121 }, 122 }, 123 }, nil) 124 cli.EXPECT().Ctx().Return(context.Background()) 125 c := &cluster{ 126 values: make(map[string]map[string]string), 127 } 128 c.load(cli, "any") 129 } 130 131 func TestCluster_Watch(t *testing.T) { 132 tests := []struct { 133 name string 134 method int 135 eventType mvccpb.Event_EventType 136 }{ 137 { 138 name: "add", 139 eventType: clientv3.EventTypePut, 140 }, 141 { 142 name: "delete", 143 eventType: clientv3.EventTypeDelete, 144 }, 145 } 146 147 for _, test := range tests { 148 t.Run(test.name, func(t *testing.T) { 149 ctrl := gomock.NewController(t) 150 defer ctrl.Finish() 151 cli := NewMockEtcdClient(ctrl) 152 restore := setMockClient(cli) 153 defer restore() 154 ch := make(chan clientv3.WatchResponse) 155 cli.EXPECT().Watch(gomock.Any(), "any/", gomock.Any()).Return(ch) 156 cli.EXPECT().Ctx().Return(context.Background()) 157 var wg sync.WaitGroup 158 wg.Add(1) 159 c := &cluster{ 160 listeners: make(map[string][]UpdateListener), 161 values: make(map[string]map[string]string), 162 } 163 listener := NewMockUpdateListener(ctrl) 164 c.listeners["any"] = []UpdateListener{listener} 165 listener.EXPECT().OnAdd(gomock.Any()).Do(func(kv KV) { 166 assert.Equal(t, "hello", kv.Key) 167 assert.Equal(t, "world", kv.Val) 168 wg.Done() 169 }).MaxTimes(1) 170 listener.EXPECT().OnDelete(gomock.Any()).Do(func(_ interface{}) { 171 wg.Done() 172 }).MaxTimes(1) 173 go c.watch(cli, "any", 0) 174 ch <- clientv3.WatchResponse{ 175 Events: []*clientv3.Event{ 176 { 177 Type: test.eventType, 178 Kv: &mvccpb.KeyValue{ 179 Key: []byte("hello"), 180 Value: []byte("world"), 181 }, 182 }, 183 }, 184 } 185 wg.Wait() 186 }) 187 } 188 } 189 190 func TestClusterWatch_RespFailures(t *testing.T) { 191 resps := []clientv3.WatchResponse{ 192 { 193 Canceled: true, 194 }, 195 { 196 // cause resp.Err() != nil 197 CompactRevision: 1, 198 }, 199 } 200 201 for _, resp := range resps { 202 t.Run(stringx.Rand(), func(t *testing.T) { 203 ctrl := gomock.NewController(t) 204 defer ctrl.Finish() 205 cli := NewMockEtcdClient(ctrl) 206 restore := setMockClient(cli) 207 defer restore() 208 ch := make(chan clientv3.WatchResponse) 209 cli.EXPECT().Watch(gomock.Any(), "any/", gomock.Any()).Return(ch).AnyTimes() 210 cli.EXPECT().Ctx().Return(context.Background()).AnyTimes() 211 c := new(cluster) 212 c.done = make(chan lang.PlaceholderType) 213 go func() { 214 ch <- resp 215 close(c.done) 216 }() 217 c.watch(cli, "any", 0) 218 }) 219 } 220 } 221 222 func TestClusterWatch_CloseChan(t *testing.T) { 223 ctrl := gomock.NewController(t) 224 defer ctrl.Finish() 225 cli := NewMockEtcdClient(ctrl) 226 restore := setMockClient(cli) 227 defer restore() 228 ch := make(chan clientv3.WatchResponse) 229 cli.EXPECT().Watch(gomock.Any(), "any/", gomock.Any()).Return(ch).AnyTimes() 230 cli.EXPECT().Ctx().Return(context.Background()).AnyTimes() 231 c := new(cluster) 232 c.done = make(chan lang.PlaceholderType) 233 go func() { 234 close(ch) 235 close(c.done) 236 }() 237 c.watch(cli, "any", 0) 238 } 239 240 func TestValueOnlyContext(t *testing.T) { 241 ctx := contextx.ValueOnlyFrom(context.Background()) 242 ctx.Done() 243 assert.Nil(t, ctx.Err()) 244 }