github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans/netpollmux/mux_pool_test.go (about) 1 /* 2 * Copyright 2021 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package netpollmux 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "math/rand" 24 "net" 25 "testing" 26 "time" 27 28 "github.com/golang/mock/gomock" 29 30 mocksnetpoll "github.com/cloudwego/kitex/internal/mocks/netpoll" 31 mocksremote "github.com/cloudwego/kitex/internal/mocks/remote" 32 33 "github.com/cloudwego/kitex/internal/test" 34 dialer "github.com/cloudwego/kitex/pkg/remote" 35 "github.com/cloudwego/kitex/pkg/utils" 36 ) 37 38 var ( 39 mockAddr0 = "127.0.0.1:8000" 40 mockAddr1 = "127.0.0.1:8001" 41 ) 42 43 func TestMuxConnPoolGetTimeout(t *testing.T) { 44 ctrl := gomock.NewController(t) 45 defer ctrl.Finish() 46 47 p := NewMuxConnPool(1) 48 49 d := mocksremote.NewMockDialer(ctrl) 50 d.EXPECT().DialTimeout(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(network, address string, timeout time.Duration) (net.Conn, error) { 51 connectCost := time.Millisecond * 10 52 if timeout < connectCost { 53 return nil, errors.New("connect timeout") 54 } 55 na := utils.NewNetAddr(network, address) 56 conn := mocksnetpoll.NewMockConnection(ctrl) 57 conn.EXPECT().RemoteAddr().Return(na).AnyTimes() 58 conn.EXPECT().SetOnRequest(gomock.Any()) 59 conn.EXPECT().AddCloseCallback(gomock.Any()) 60 conn.EXPECT().IsActive().Return(false).AnyTimes() 61 return conn, nil 62 }).AnyTimes() 63 64 var err error 65 66 _, err = p.Get(context.TODO(), "tcp", mockAddr0, dialer.ConnOption{Dialer: d, ConnectTimeout: time.Second}) 67 test.Assert(t, err == nil) 68 69 _, err = p.Get(context.TODO(), "tcp", mockAddr0, dialer.ConnOption{Dialer: d, ConnectTimeout: time.Millisecond}) 70 test.Assert(t, err != nil) 71 } 72 73 func TestMuxConnPoolReuse(t *testing.T) { 74 ctrl := gomock.NewController(t) 75 defer ctrl.Finish() 76 77 p := NewMuxConnPool(1) 78 79 d := mocksremote.NewMockDialer(ctrl) 80 d.EXPECT().DialTimeout(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(network, address string, timeout time.Duration) (net.Conn, error) { 81 na := utils.NewNetAddr(network, address) 82 conn := mocksnetpoll.NewMockConnection(ctrl) 83 conn.EXPECT().RemoteAddr().Return(na).AnyTimes() 84 conn.EXPECT().SetOnRequest(gomock.Any()) 85 conn.EXPECT().AddCloseCallback(gomock.Any()) 86 conn.EXPECT().IsActive().Return(true).AnyTimes() 87 return conn, nil 88 }).AnyTimes() 89 90 addr1, addr2 := mockAddr1, "127.0.0.1:8002" 91 opt := dialer.ConnOption{Dialer: d, ConnectTimeout: time.Second} 92 93 count := make(map[net.Conn]int) 94 for i := 0; i < 10; i++ { 95 c, err := p.Get(context.TODO(), "tcp", addr1, opt) 96 test.Assert(t, err == nil) 97 count[c]++ 98 } 99 test.Assert(t, len(count) == 1) 100 101 count = make(map[net.Conn]int) 102 for i := 0; i < 10; i++ { 103 c, err := p.Get(context.TODO(), "tcp", addr1, opt) 104 test.Assert(t, err == nil) 105 err = p.Put(c) 106 test.Assert(t, err == nil) 107 count[c]++ 108 } 109 test.Assert(t, len(count) == 1) 110 111 count = make(map[net.Conn]int) 112 for i := 0; i < 10; i++ { 113 c, err := p.Get(context.TODO(), "tcp", addr1, opt) 114 test.Assert(t, err == nil) 115 err = p.Put(c) 116 test.Assert(t, err == nil) 117 count[c]++ 118 119 c, err = p.Get(context.TODO(), "tcp", addr2, opt) 120 test.Assert(t, err == nil) 121 err = p.Put(c) 122 test.Assert(t, err == nil) 123 count[c]++ 124 } 125 test.Assert(t, len(count) == 2) 126 } 127 128 func TestMuxConnPoolDiscardClean(t *testing.T) { 129 ctrl := gomock.NewController(t) 130 defer ctrl.Finish() 131 132 size := 4 133 conn := mocksnetpoll.NewMockConnection(ctrl) 134 d := mocksremote.NewMockDialer(ctrl) 135 d.EXPECT().DialTimeout(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(network, address string, timeout time.Duration) (net.Conn, error) { 136 conn.EXPECT().Close().Return(nil).Times(0) 137 conn.EXPECT().IsActive().Return(true).AnyTimes() 138 conn.EXPECT().SetOnRequest(gomock.Any()) 139 conn.EXPECT().AddCloseCallback(gomock.Any()) 140 return conn, nil 141 }).AnyTimes() 142 143 p := NewMuxConnPool(size) 144 145 network, address := "tcp", mockAddr0 146 var conns []net.Conn 147 for i := 0; i < 1024; i++ { 148 conn, err := p.Get(context.TODO(), network, address, dialer.ConnOption{Dialer: d}) 149 test.Assert(t, err == nil) 150 conns = append(conns, conn) 151 } 152 for i := 0; i < 128; i++ { 153 p.Discard(conns[i]) 154 } 155 conn.EXPECT().Close().Return(nil).Times(size) 156 p.Clean(network, address) 157 } 158 159 func TestMuxConnPoolClose(t *testing.T) { 160 ctrl := gomock.NewController(t) 161 defer ctrl.Finish() 162 163 conn := mocksnetpoll.NewMockConnection(ctrl) 164 conn.EXPECT().Close().Return(nil).Times(2) 165 conn.EXPECT().IsActive().Return(true).AnyTimes() 166 conn.EXPECT().SetOnRequest(gomock.Any()).AnyTimes() 167 conn.EXPECT().AddCloseCallback(gomock.Any()).AnyTimes() 168 d := mocksremote.NewMockDialer(ctrl) 169 d.EXPECT().DialTimeout(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(network, address string, timeout time.Duration) (net.Conn, error) { 170 return conn, nil 171 }).AnyTimes() 172 173 p := NewMuxConnPool(1) 174 175 network, address := "tcp", mockAddr0 176 _, err := p.Get(context.TODO(), network, address, dialer.ConnOption{Dialer: d}) 177 test.Assert(t, err == nil) 178 179 network, address = "tcp", mockAddr1 180 _, err = p.Get(context.TODO(), network, address, dialer.ConnOption{Dialer: d}) 181 test.Assert(t, err == nil) 182 183 connCount := 0 184 p.connMap.Range(func(key, value interface{}) bool { 185 connCount++ 186 return true 187 }) 188 test.Assert(t, connCount == 2) 189 190 p.Close() 191 192 connCount = 0 193 p.connMap.Range(func(key, value interface{}) bool { 194 connCount++ 195 return true 196 }) 197 test.Assert(t, connCount == 0) 198 } 199 200 func BenchmarkMuxPoolGetOne(b *testing.B) { 201 ctrl := gomock.NewController(b) 202 defer ctrl.Finish() 203 204 d := mocksremote.NewMockDialer(ctrl) 205 d.EXPECT().DialTimeout(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(network, address string, timeout time.Duration) (net.Conn, error) { 206 na := utils.NewNetAddr(network, address) 207 conn := mocksnetpoll.NewMockConnection(ctrl) 208 conn.EXPECT().RemoteAddr().Return(na).AnyTimes() 209 conn.EXPECT().SetOnRequest(gomock.Any()).AnyTimes() 210 conn.EXPECT().AddCloseCallback(gomock.Any()).AnyTimes() 211 conn.EXPECT().IsActive().Return(false).AnyTimes() 212 conn.EXPECT().Close().Return(nil).AnyTimes() 213 return conn, nil 214 }).AnyTimes() 215 p := NewMuxConnPool(1) 216 opt := dialer.ConnOption{Dialer: d, ConnectTimeout: time.Second} 217 218 b.ResetTimer() 219 b.ReportAllocs() 220 b.RunParallel(func(pb *testing.PB) { 221 for pb.Next() { 222 p.Get(context.TODO(), "tcp", mockAddr1, opt) 223 } 224 }) 225 } 226 227 func BenchmarkMuxPoolGetRand2000(b *testing.B) { 228 ctrl := gomock.NewController(b) 229 defer ctrl.Finish() 230 231 d := mocksremote.NewMockDialer(ctrl) 232 d.EXPECT().DialTimeout(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(network, address string, timeout time.Duration) (net.Conn, error) { 233 na := utils.NewNetAddr(network, address) 234 conn := mocksnetpoll.NewMockConnection(ctrl) 235 conn.EXPECT().RemoteAddr().Return(na).AnyTimes() 236 conn.EXPECT().SetOnRequest(gomock.Any()).AnyTimes() 237 conn.EXPECT().AddCloseCallback(gomock.Any()).AnyTimes() 238 conn.EXPECT().IsActive().Return(false).AnyTimes() 239 conn.EXPECT().Close().Return(nil).AnyTimes() 240 return conn, nil 241 }).AnyTimes() 242 p := NewMuxConnPool(1) 243 opt := dialer.ConnOption{Dialer: d, ConnectTimeout: time.Second} 244 245 var addrs []string 246 for i := 0; i < 2000; i++ { 247 addrs = append(addrs, fmt.Sprintf("127.0.0.1:%d", 8000+rand.Intn(10000))) 248 } 249 b.ResetTimer() 250 b.ReportAllocs() 251 b.RunParallel(func(pb *testing.PB) { 252 for pb.Next() { 253 p.Get(context.TODO(), "tcp", addrs[rand.Intn(2000)], opt) 254 } 255 }) 256 } 257 258 func BenchmarkMuxPoolGetRand2000Mesh(b *testing.B) { 259 ctrl := gomock.NewController(b) 260 defer ctrl.Finish() 261 262 d := mocksremote.NewMockDialer(ctrl) 263 d.EXPECT().DialTimeout(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(network, address string, timeout time.Duration) (net.Conn, error) { 264 na := utils.NewNetAddr(network, address) 265 conn := mocksnetpoll.NewMockConnection(ctrl) 266 conn.EXPECT().RemoteAddr().Return(na).AnyTimes() 267 conn.EXPECT().SetOnRequest(gomock.Any()).AnyTimes() 268 conn.EXPECT().AddCloseCallback(gomock.Any()).AnyTimes() 269 conn.EXPECT().IsActive().Return(false).AnyTimes() 270 conn.EXPECT().Close().Return(nil).AnyTimes() 271 return conn, nil 272 }).AnyTimes() 273 p := NewMuxConnPool(1) 274 opt := dialer.ConnOption{Dialer: d, ConnectTimeout: time.Second} 275 276 var addrs []string 277 for i := 0; i < 2000; i++ { 278 addrs = append(addrs, fmt.Sprintf("127.0.0.1:%d", 8000+rand.Intn(10000))) 279 } 280 b.ResetTimer() 281 b.ReportAllocs() 282 b.RunParallel(func(pb *testing.PB) { 283 for pb.Next() { 284 p.Get(context.TODO(), "tcp", addrs[rand.Intn(2000)], opt) 285 } 286 }) 287 }