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