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  }