github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/tools/querytee/proxy_endpoint_test.go (about) 1 package querytee 2 3 import ( 4 "net/url" 5 "testing" 6 "time" 7 8 "github.com/go-kit/log" 9 "github.com/pkg/errors" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func Test_ProxyEndpoint_waitBackendResponseForDownstream(t *testing.T) { 15 backendURL1, err := url.Parse("http://backend-1/") 16 require.NoError(t, err) 17 backendURL2, err := url.Parse("http://backend-2/") 18 require.NoError(t, err) 19 backendURL3, err := url.Parse("http://backend-3/") 20 require.NoError(t, err) 21 22 backendPref := NewProxyBackend("backend-1", backendURL1, time.Second, true) 23 backendOther1 := NewProxyBackend("backend-2", backendURL2, time.Second, false) 24 backendOther2 := NewProxyBackend("backend-3", backendURL3, time.Second, false) 25 26 tests := map[string]struct { 27 backends []*ProxyBackend 28 responses []*backendResponse 29 expected *ProxyBackend 30 }{ 31 "the preferred backend is the 1st response received": { 32 backends: []*ProxyBackend{backendPref, backendOther1}, 33 responses: []*backendResponse{ 34 {backend: backendPref, status: 200}, 35 }, 36 expected: backendPref, 37 }, 38 "the preferred backend is the last response received": { 39 backends: []*ProxyBackend{backendPref, backendOther1}, 40 responses: []*backendResponse{ 41 {backend: backendOther1, status: 200}, 42 {backend: backendPref, status: 200}, 43 }, 44 expected: backendPref, 45 }, 46 "the preferred backend is the last response received but it's not successful": { 47 backends: []*ProxyBackend{backendPref, backendOther1}, 48 responses: []*backendResponse{ 49 {backend: backendOther1, status: 200}, 50 {backend: backendPref, status: 500}, 51 }, 52 expected: backendOther1, 53 }, 54 "the preferred backend is the 2nd response received but only the last one is successful": { 55 backends: []*ProxyBackend{backendPref, backendOther1, backendOther2}, 56 responses: []*backendResponse{ 57 {backend: backendOther1, status: 500}, 58 {backend: backendPref, status: 500}, 59 {backend: backendOther2, status: 200}, 60 }, 61 expected: backendOther2, 62 }, 63 "there's no preferred backend configured and the 1st response is successful": { 64 backends: []*ProxyBackend{backendOther1, backendOther2}, 65 responses: []*backendResponse{ 66 {backend: backendOther1, status: 200}, 67 }, 68 expected: backendOther1, 69 }, 70 "there's no preferred backend configured and the last response is successful": { 71 backends: []*ProxyBackend{backendOther1, backendOther2}, 72 responses: []*backendResponse{ 73 {backend: backendOther1, status: 500}, 74 {backend: backendOther2, status: 200}, 75 }, 76 expected: backendOther2, 77 }, 78 "no received response is successful": { 79 backends: []*ProxyBackend{backendPref, backendOther1}, 80 responses: []*backendResponse{ 81 {backend: backendOther1, status: 500}, 82 {backend: backendPref, status: 500}, 83 }, 84 expected: backendOther1, 85 }, 86 } 87 88 for testName, testData := range tests { 89 testData := testData 90 91 t.Run(testName, func(t *testing.T) { 92 endpoint := NewProxyEndpoint(testData.backends, "test", NewProxyMetrics(nil), log.NewNopLogger(), nil) 93 94 // Send the responses from a dedicated goroutine. 95 resCh := make(chan *backendResponse) 96 go func() { 97 for _, res := range testData.responses { 98 resCh <- res 99 } 100 close(resCh) 101 }() 102 103 // Wait for the selected backend response. 104 actual := endpoint.waitBackendResponseForDownstream(resCh) 105 assert.Equal(t, testData.expected, actual.backend) 106 }) 107 } 108 } 109 110 func Test_backendResponse_succeeded(t *testing.T) { 111 tests := map[string]struct { 112 resStatus int 113 resError error 114 expected bool 115 }{ 116 "Error while executing request": { 117 resStatus: 0, 118 resError: errors.New("network error"), 119 expected: false, 120 }, 121 "2xx response status code": { 122 resStatus: 200, 123 resError: nil, 124 expected: true, 125 }, 126 "3xx response status code": { 127 resStatus: 300, 128 resError: nil, 129 expected: false, 130 }, 131 "4xx response status code": { 132 resStatus: 400, 133 resError: nil, 134 expected: true, 135 }, 136 "5xx response status code": { 137 resStatus: 500, 138 resError: nil, 139 expected: false, 140 }, 141 } 142 143 for testName, testData := range tests { 144 t.Run(testName, func(t *testing.T) { 145 res := &backendResponse{ 146 status: testData.resStatus, 147 err: testData.resError, 148 } 149 150 assert.Equal(t, testData.expected, res.succeeded()) 151 }) 152 } 153 } 154 155 func Test_backendResponse_statusCode(t *testing.T) { 156 tests := map[string]struct { 157 resStatus int 158 resError error 159 expected int 160 }{ 161 "Error while executing request": { 162 resStatus: 0, 163 resError: errors.New("network error"), 164 expected: 500, 165 }, 166 "200 response status code": { 167 resStatus: 200, 168 resError: nil, 169 expected: 200, 170 }, 171 "503 response status code": { 172 resStatus: 503, 173 resError: nil, 174 expected: 503, 175 }, 176 } 177 178 for testName, testData := range tests { 179 t.Run(testName, func(t *testing.T) { 180 res := &backendResponse{ 181 status: testData.resStatus, 182 err: testData.resError, 183 } 184 185 assert.Equal(t, testData.expected, res.statusCode()) 186 }) 187 } 188 }