github.com/network-quality/goresponsiveness@v0.0.0-20240129151524-343954285090/traceable/traceable_test.go (about) 1 /* 2 * This file is part of Go Responsiveness. 3 * 4 * Go Responsiveness is free software: you can redistribute it and/or modify it under 5 * the terms of the GNU General Public License as published by the Free Software Foundation, 6 * either version 2 of the License, or (at your option) any later version. 7 * Go Responsiveness is distributed in the hope that it will be useful, but WITHOUT ANY 8 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 9 * PARTICULAR PURPOSE. See the GNU General Public License for more details. 10 * 11 * You should have received a copy of the GNU General Public License along 12 * with Go Responsiveness. If not, see <https://www.gnu.org/licenses/>. 13 */ 14 15 package traceable 16 17 import ( 18 "context" 19 "crypto/tls" 20 "io" 21 "net/http" 22 "net/http/httptrace" 23 "sync" 24 "sync/atomic" 25 "testing" 26 "time" 27 28 "github.com/network-quality/goresponsiveness/debug" 29 ) 30 31 type CountingTraceable struct { 32 Counter *uint64 33 } 34 35 func (lgd *CountingTraceable) SetDnsStartTimeInfo( 36 now time.Time, 37 dnsStartInfo httptrace.DNSStartInfo, 38 ) { 39 40 } 41 42 func (lgd *CountingTraceable) SetDnsDoneTimeInfo( 43 now time.Time, 44 dnsDoneInfo httptrace.DNSDoneInfo, 45 ) { 46 47 } 48 49 func (lgd *CountingTraceable) SetConnectStartTime( 50 now time.Time, 51 ) { 52 53 } 54 55 func (lgd *CountingTraceable) SetConnectDoneTimeError( 56 now time.Time, 57 err error, 58 ) { 59 60 } 61 62 func (lgd *CountingTraceable) SetGetConnTime(now time.Time) { 63 } 64 65 func (lgd *CountingTraceable) SetGotConnTimeInfo( 66 now time.Time, 67 gotConnInfo httptrace.GotConnInfo, 68 ) { 69 atomic.AddUint64(lgd.Counter, 1) 70 } 71 72 func (lgd *CountingTraceable) SetTLSHandshakeStartTime( 73 now time.Time, 74 ) { 75 } 76 77 func (lgd *CountingTraceable) SetTLSHandshakeDoneTimeState( 78 now time.Time, 79 connectionState tls.ConnectionState, 80 ) { 81 } 82 83 func (lgd *CountingTraceable) SetHttpWroteRequestTimeInfo( 84 now time.Time, 85 info httptrace.WroteRequestInfo, 86 ) { 87 } 88 89 func (lgd *CountingTraceable) SetHttpResponseReadyTime( 90 now time.Time, 91 ) { 92 } 93 94 // Ensure that two different http client request tracers started with the same context 95 // do not compose and receive each other's callbacks. 96 func TestDuplicativeTraceables(t *testing.T) { 97 98 singleCtx, singleCtxCancel_ := context.WithCancel(context.Background()) 99 defer singleCtxCancel_() 100 101 client := http.Client{} 102 103 counterA := new(uint64) 104 countingTracerA := CountingTraceable{Counter: counterA} 105 counterB := new(uint64) 106 countingTracerB := CountingTraceable{Counter: counterB} 107 108 debugging := debug.NewDebugWithPrefix(debug.Debug, "TestDuplicativeTraceables") 109 request_a, err := http.NewRequestWithContext( 110 httptrace.WithClientTrace( 111 singleCtx, 112 GenerateHttpTimingTracer(&countingTracerA, debugging.Level), 113 ), 114 "GET", 115 "https://www.google.com/", 116 nil, 117 ) 118 if err != nil { 119 t.Fatalf("Failed to create request A to GET google.com") 120 } 121 request_b, err := http.NewRequestWithContext( 122 httptrace.WithClientTrace( 123 singleCtx, 124 GenerateHttpTimingTracer(&countingTracerB, debugging.Level), 125 ), 126 "GET", 127 "https://www.google.com/", 128 nil, 129 ) 130 if err != nil { 131 t.Fatalf("Failed to create request B to GET google.com") 132 } 133 134 requestWg := new(sync.WaitGroup) 135 136 requestWg.Add(2) 137 go func() { 138 defer requestWg.Done() 139 get, err := client.Do(request_a) 140 if err != nil { 141 return 142 } 143 _, _ = io.Copy(io.Discard, get.Body) 144 get.Body.Close() 145 }() 146 go func() { 147 defer requestWg.Done() 148 get, err := client.Do(request_b) 149 if err != nil { 150 return 151 } 152 _, _ = io.Copy(io.Discard, get.Body) 153 get.Body.Close() 154 }() 155 156 requestWg.Wait() 157 158 if !(*counterA == 1 && *counterB == 1) { 159 t.Fatalf( 160 "Two separate tracers received overlapping callbacks on each other's http requests: (counterA: %d, counterB: %d)", 161 *counterA, 162 *counterB, 163 ) 164 } 165 166 }