gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/gmhttp/export_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Bridge package to expose http internals to tests in the http_test 6 // package. 7 8 package gmhttp 9 10 import ( 11 "context" 12 "fmt" 13 "net" 14 "net/url" 15 "sort" 16 "sync" 17 "testing" 18 "time" 19 ) 20 21 //goland:noinspection GoSnakeCaseUsage 22 var ( 23 DefaultUserAgent = defaultUserAgent 24 NewLoggingConn = newLoggingConn 25 ExportAppendTime = appendTime 26 ExportRefererForURL = refererForURL 27 ExportServerNewConn = (*Server).newConn 28 ExportCloseWriteAndWait = (*conn).closeWriteAndWait 29 ExportErrRequestCanceled = errRequestCanceled 30 ExportErrRequestCanceledConn = errRequestCanceledConn 31 ExportErrServerClosedIdle = errServerClosedIdle 32 ExportServeFile = serveFile 33 ExportScanETag = scanETag 34 ExportHttp2ConfigureServer = http2ConfigureServer 35 Export_shouldCopyHeaderOnRedirect = shouldCopyHeaderOnRedirect 36 Export_writeStatusLine = writeStatusLine 37 Export_is408Message = is408Message 38 ) 39 40 const MaxWriteWaitBeforeConnReuse = maxWriteWaitBeforeConnReuse 41 42 func init() { 43 // We only want to pay for this cost during testing. 44 // When not under test, these values are always nil 45 // and never assigned to. 46 testHookMu = new(sync.Mutex) 47 48 testHookClientDoResult = func(res *Response, err error) { 49 if err != nil { 50 if _, ok := err.(*url.Error); !ok { 51 panic(fmt.Sprintf("unexpected Client.Do error of type %T; want *url.Error", err)) 52 } 53 } else { 54 if res == nil { 55 panic("Client.Do returned nil, nil") 56 } 57 if res.Body == nil { 58 panic("Client.Do returned nil res.Body and no error") 59 } 60 } 61 } 62 } 63 64 func CondSkipHTTP2(t *testing.T) { 65 if omitBundledHTTP2 { 66 t.Skip("skipping HTTP/2 test when nethttpomithttp2 build tag in use") 67 } 68 } 69 70 var ( 71 SetEnterRoundTripHook = hookSetter(&testHookEnterRoundTrip) 72 SetRoundTripRetried = hookSetter(&testHookRoundTripRetried) 73 ) 74 75 func SetReadLoopBeforeNextReadHook(f func()) { 76 testHookMu.Lock() 77 defer testHookMu.Unlock() 78 unnilTestHook(&f) 79 testHookReadLoopBeforeNextRead = f 80 } 81 82 // SetPendingDialHooks sets the hooks that run before and after handling 83 // pending dials. 84 func SetPendingDialHooks(before, after func()) { 85 unnilTestHook(&before) 86 unnilTestHook(&after) 87 testHookPrePendingDial, testHookPostPendingDial = before, after 88 } 89 90 func SetTestHookServerServe(fn func(*Server, net.Listener)) { testHookServerServe = fn } 91 92 func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler { 93 ctx, cancel := context.WithCancel(context.Background()) 94 go func() { 95 <-ch 96 cancel() 97 }() 98 return &timeoutHandler{ 99 handler: handler, 100 testContext: ctx, 101 // (no body) 102 } 103 } 104 105 func ResetCachedEnvironment() { 106 resetProxyConfig() 107 } 108 109 func (t *Transport) NumPendingRequestsForTesting() int { 110 t.reqMu.Lock() 111 defer t.reqMu.Unlock() 112 return len(t.reqCanceler) 113 } 114 115 func (t *Transport) IdleConnKeysForTesting() (keys []string) { 116 keys = make([]string, 0) 117 t.idleMu.Lock() 118 defer t.idleMu.Unlock() 119 for key := range t.idleConn { 120 keys = append(keys, key.String()) 121 } 122 sort.Strings(keys) 123 return 124 } 125 126 func (t *Transport) IdleConnKeyCountForTesting() int { 127 t.idleMu.Lock() 128 defer t.idleMu.Unlock() 129 return len(t.idleConn) 130 } 131 132 func (t *Transport) IdleConnStrsForTesting() []string { 133 var ret []string 134 t.idleMu.Lock() 135 defer t.idleMu.Unlock() 136 for _, conns := range t.idleConn { 137 for _, pc := range conns { 138 ret = append(ret, pc.conn.LocalAddr().String()+"/"+pc.conn.RemoteAddr().String()) 139 } 140 } 141 sort.Strings(ret) 142 return ret 143 } 144 145 //goland:noinspection GoSnakeCaseUsage 146 func (t *Transport) IdleConnStrsForTesting_h2() []string { 147 var ret []string 148 noDialPool := t.h2transport.(*http2Transport).ConnPool.(http2noDialClientConnPool) 149 pool := noDialPool.http2clientConnPool 150 151 pool.mu.Lock() 152 defer pool.mu.Unlock() 153 154 for k, cc := range pool.conns { 155 for range cc { 156 ret = append(ret, k) 157 } 158 } 159 160 sort.Strings(ret) 161 return ret 162 } 163 164 func (t *Transport) IdleConnCountForTesting(scheme, addr string) int { 165 t.idleMu.Lock() 166 defer t.idleMu.Unlock() 167 key := connectMethodKey{"", scheme, addr, false} 168 cacheKey := key.String() 169 for k, conns := range t.idleConn { 170 if k.String() == cacheKey { 171 return len(conns) 172 } 173 } 174 return 0 175 } 176 177 func (t *Transport) IdleConnWaitMapSizeForTesting() int { 178 t.idleMu.Lock() 179 defer t.idleMu.Unlock() 180 return len(t.idleConnWait) 181 } 182 183 func (t *Transport) IsIdleForTesting() bool { 184 t.idleMu.Lock() 185 defer t.idleMu.Unlock() 186 return t.closeIdle 187 } 188 189 func (t *Transport) QueueForIdleConnForTesting() { 190 t.queueForIdleConn(nil) 191 } 192 193 // PutIdleTestConn reports whether it was able to insert a fresh 194 // persistConn for scheme, addr into the idle connection pool. 195 func (t *Transport) PutIdleTestConn(scheme, addr string) bool { 196 c, _ := net.Pipe() 197 key := connectMethodKey{"", scheme, addr, false} 198 199 if t.MaxConnsPerHost > 0 { 200 // Transport is tracking conns-per-host. 201 // Increment connection count to account 202 // for new persistConn created below. 203 t.connsPerHostMu.Lock() 204 if t.connsPerHost == nil { 205 t.connsPerHost = make(map[connectMethodKey]int) 206 } 207 t.connsPerHost[key]++ 208 t.connsPerHostMu.Unlock() 209 } 210 211 return t.tryPutIdleConn(&persistConn{ 212 t: t, 213 conn: c, // dummy 214 closech: make(chan struct{}), // so it can be closed 215 cacheKey: key, 216 }) == nil 217 } 218 219 // PutIdleTestConnH2 reports whether it was able to insert a fresh 220 // HTTP/2 persistConn for scheme, addr into the idle connection pool. 221 func (t *Transport) PutIdleTestConnH2(scheme, addr string, alt RoundTripper) bool { 222 key := connectMethodKey{"", scheme, addr, false} 223 224 if t.MaxConnsPerHost > 0 { 225 // Transport is tracking conns-per-host. 226 // Increment connection count to account 227 // for new persistConn created below. 228 t.connsPerHostMu.Lock() 229 if t.connsPerHost == nil { 230 t.connsPerHost = make(map[connectMethodKey]int) 231 } 232 t.connsPerHost[key]++ 233 t.connsPerHostMu.Unlock() 234 } 235 236 return t.tryPutIdleConn(&persistConn{ 237 t: t, 238 alt: alt, 239 cacheKey: key, 240 }) == nil 241 } 242 243 // All test hooks must be non-nil so they can be called directly, 244 // but the tests use nil to mean hook disabled. 245 func unnilTestHook(f *func()) { 246 if *f == nil { 247 *f = nop 248 } 249 } 250 251 func hookSetter(dst *func()) func(func()) { 252 return func(fn func()) { 253 unnilTestHook(&fn) 254 *dst = fn 255 } 256 } 257 258 func ExportHttp2ConfigureTransport(t *Transport) error { 259 t2, err := http2configureTransports(t) 260 if err != nil { 261 return err 262 } 263 t.h2transport = t2 264 return nil 265 } 266 267 func (srv *Server) ExportAllConnsIdle() bool { 268 srv.mu.Lock() 269 defer srv.mu.Unlock() 270 for c := range srv.activeConn { 271 st, unixSec := c.getState() 272 if unixSec == 0 || st != StateIdle { 273 return false 274 } 275 } 276 return true 277 } 278 279 func (srv *Server) ExportAllConnsByState() map[ConnState]int { 280 states := map[ConnState]int{} 281 srv.mu.Lock() 282 defer srv.mu.Unlock() 283 for c := range srv.activeConn { 284 st, _ := c.getState() 285 states[st] += 1 286 } 287 return states 288 } 289 290 func (r *Request) WithT(t *testing.T) *Request { 291 return r.WithContext(context.WithValue(r.Context(), tLogKey{}, t.Logf)) 292 } 293 294 func ExportSetH2GoawayTimeout(d time.Duration) (restore func()) { 295 old := http2goAwayTimeout 296 http2goAwayTimeout = d 297 return func() { http2goAwayTimeout = old } 298 } 299 300 func (r *Request) ExportIsReplayable() bool { return r.isReplayable() } 301 302 // ExportCloseTransportConnsAbruptly closes all idle connections from 303 // tr in an abrupt way, just reaching into the underlying Conns and 304 // closing them, without telling the Transport or its persistConns 305 // that it's doing so. This is to simulate the server closing connections 306 // on the Transport. 307 func ExportCloseTransportConnsAbruptly(tr *Transport) { 308 tr.idleMu.Lock() 309 for _, pcs := range tr.idleConn { 310 for _, pc := range pcs { 311 _ = pc.conn.Close() 312 } 313 } 314 tr.idleMu.Unlock() 315 }