github.com/prebid/prebid-server@v0.275.0/prebid_cache_client/client_test.go (about)

     1  package prebid_cache_client
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"strconv"
    11  	"testing"
    12  
    13  	"github.com/prebid/prebid-server/config"
    14  	"github.com/prebid/prebid-server/metrics"
    15  	metricsConf "github.com/prebid/prebid-server/metrics/config"
    16  
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/mock"
    19  )
    20  
    21  func TestEmptyPut(t *testing.T) {
    22  	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    23  		t.Errorf("The server should not be called.")
    24  	})
    25  	server := httptest.NewServer(handler)
    26  	defer server.Close()
    27  
    28  	metricsMock := &metrics.MetricsEngineMock{}
    29  
    30  	client := &clientImpl{
    31  		httpClient: server.Client(),
    32  		putUrl:     server.URL,
    33  		metrics:    metricsMock,
    34  	}
    35  	ids, _ := client.PutJson(context.Background(), nil)
    36  	assertIntEqual(t, len(ids), 0)
    37  	ids, _ = client.PutJson(context.Background(), []Cacheable{})
    38  	assertIntEqual(t, len(ids), 0)
    39  
    40  	metricsMock.AssertNotCalled(t, "RecordPrebidCacheRequestTime")
    41  }
    42  
    43  func TestBadResponse(t *testing.T) {
    44  	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    45  		w.WriteHeader(500)
    46  	})
    47  	server := httptest.NewServer(handler)
    48  	defer server.Close()
    49  
    50  	metricsMock := &metrics.MetricsEngineMock{}
    51  	metricsMock.On("RecordPrebidCacheRequestTime", true, mock.Anything).Once()
    52  
    53  	client := &clientImpl{
    54  		httpClient: server.Client(),
    55  		putUrl:     server.URL,
    56  		metrics:    metricsMock,
    57  	}
    58  	ids, _ := client.PutJson(context.Background(), []Cacheable{
    59  		{
    60  			Type: TypeJSON,
    61  			Data: json.RawMessage("true"),
    62  		}, {
    63  			Type: TypeJSON,
    64  			Data: json.RawMessage("false"),
    65  		},
    66  	})
    67  	assertIntEqual(t, len(ids), 2)
    68  	assertStringEqual(t, ids[0], "")
    69  	assertStringEqual(t, ids[1], "")
    70  
    71  	metricsMock.AssertExpectations(t)
    72  }
    73  
    74  func TestCancelledContext(t *testing.T) {
    75  	testCases := []struct {
    76  		description         string
    77  		cacheable           []Cacheable
    78  		expectedItems       int
    79  		expectedPayloadSize int
    80  	}{
    81  		{
    82  			description: "1 Item",
    83  			cacheable: []Cacheable{
    84  				{
    85  					Type: TypeJSON,
    86  					Data: json.RawMessage("true"),
    87  				},
    88  			},
    89  			expectedItems:       1,
    90  			expectedPayloadSize: 39,
    91  		},
    92  		{
    93  			description: "2 Items",
    94  			cacheable: []Cacheable{
    95  				{
    96  					Type: TypeJSON,
    97  					Data: json.RawMessage("true"),
    98  				},
    99  				{
   100  					Type: TypeJSON,
   101  					Data: json.RawMessage("false"),
   102  				},
   103  			},
   104  			expectedItems:       2,
   105  			expectedPayloadSize: 69,
   106  		},
   107  	}
   108  
   109  	// Initialize Stub Server
   110  	stubHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   111  		w.WriteHeader(200)
   112  	})
   113  	stubServer := httptest.NewServer(stubHandler)
   114  	defer stubServer.Close()
   115  
   116  	// Run Tests
   117  	for _, testCase := range testCases {
   118  		metricsMock := &metrics.MetricsEngineMock{}
   119  		metricsMock.On("RecordPrebidCacheRequestTime", false, mock.Anything).Once()
   120  
   121  		client := &clientImpl{
   122  			httpClient: stubServer.Client(),
   123  			putUrl:     stubServer.URL,
   124  			metrics:    metricsMock,
   125  		}
   126  
   127  		ctx, cancel := context.WithCancel(context.Background())
   128  		cancel()
   129  		ids, errs := client.PutJson(ctx, testCase.cacheable)
   130  
   131  		expectedErrorMessage := fmt.Sprintf("Items=%v, Payload Size=%v", testCase.expectedItems, testCase.expectedPayloadSize)
   132  
   133  		assert.Equal(t, testCase.expectedItems, len(ids), testCase.description+":ids")
   134  		assert.Len(t, errs, 1)
   135  		assert.Contains(t, errs[0].Error(), "Error sending the request to Prebid Cache: context canceled", testCase.description+":error")
   136  		assert.Contains(t, errs[0].Error(), expectedErrorMessage, testCase.description+":error_dimensions")
   137  		metricsMock.AssertExpectations(t)
   138  	}
   139  }
   140  
   141  func TestSuccessfulPut(t *testing.T) {
   142  	server := httptest.NewServer(newHandler(2))
   143  	defer server.Close()
   144  
   145  	metricsMock := &metrics.MetricsEngineMock{}
   146  	metricsMock.On("RecordPrebidCacheRequestTime", true, mock.Anything).Once()
   147  
   148  	client := &clientImpl{
   149  		httpClient: server.Client(),
   150  		putUrl:     server.URL,
   151  		metrics:    metricsMock,
   152  	}
   153  
   154  	ids, _ := client.PutJson(context.Background(), []Cacheable{
   155  		{
   156  			Type:       TypeJSON,
   157  			Data:       json.RawMessage("true"),
   158  			TTLSeconds: 300,
   159  		}, {
   160  			Type: TypeJSON,
   161  			Data: json.RawMessage("false"),
   162  		},
   163  	})
   164  	assertIntEqual(t, len(ids), 2)
   165  	assertStringEqual(t, ids[0], "0")
   166  	assertStringEqual(t, ids[1], "1")
   167  
   168  	metricsMock.AssertExpectations(t)
   169  }
   170  
   171  func TestEncodeValueToBuffer(t *testing.T) {
   172  	buf := new(bytes.Buffer)
   173  	testCache := Cacheable{
   174  		Type:       TypeJSON,
   175  		Data:       json.RawMessage(`{}`),
   176  		TTLSeconds: 300,
   177  		BidID:      "bid",
   178  		Bidder:     "bdr",
   179  		Timestamp:  123456789,
   180  	}
   181  	expected := string(`{"type":"json","ttlseconds":300,"value":{},"bidid":"bid","bidder":"bdr","timestamp":123456789}`)
   182  	_ = encodeValueToBuffer(testCache, false, buf)
   183  	actual := buf.String()
   184  	assertStringEqual(t, expected, actual)
   185  }
   186  
   187  // The following test asserts that the cache client's GetExtCacheData() implementation is able to pull return the exact Path and Host that were
   188  // specified in Prebid-Server's configuration, no substitutions nor default values.
   189  func TestStripCacheHostAndPath(t *testing.T) {
   190  	inCacheURL := config.Cache{ExpectedTimeMillis: 10}
   191  	type aTest struct {
   192  		inExtCacheURL  config.ExternalCache
   193  		expectedScheme string
   194  		expectedHost   string
   195  		expectedPath   string
   196  	}
   197  	testInput := []aTest{
   198  		{
   199  			inExtCacheURL: config.ExternalCache{
   200  				Scheme: "",
   201  				Host:   "prebid-server.prebid.org",
   202  				Path:   "/pbcache/endpoint",
   203  			},
   204  			expectedScheme: "",
   205  			expectedHost:   "prebid-server.prebid.org",
   206  			expectedPath:   "/pbcache/endpoint",
   207  		},
   208  		{
   209  			inExtCacheURL: config.ExternalCache{
   210  				Scheme: "https",
   211  				Host:   "prebid-server.prebid.org",
   212  				Path:   "/pbcache/endpoint",
   213  			},
   214  			expectedScheme: "https",
   215  			expectedHost:   "prebid-server.prebid.org",
   216  			expectedPath:   "/pbcache/endpoint",
   217  		},
   218  		{
   219  			inExtCacheURL: config.ExternalCache{
   220  				Scheme: "",
   221  				Host:   "prebidcache.net",
   222  				Path:   "",
   223  			},
   224  			expectedScheme: "",
   225  			expectedHost:   "prebidcache.net",
   226  			expectedPath:   "",
   227  		},
   228  		{
   229  			inExtCacheURL: config.ExternalCache{
   230  				Scheme: "",
   231  				Host:   "",
   232  				Path:   "",
   233  			},
   234  			expectedScheme: "",
   235  			expectedHost:   "",
   236  			expectedPath:   "",
   237  		},
   238  		{
   239  			inExtCacheURL: config.ExternalCache{
   240  				Scheme: "",
   241  				Host:   "prebid-server.prebid.org",
   242  				Path:   "pbcache/endpoint",
   243  			},
   244  			expectedScheme: "",
   245  			expectedHost:   "prebid-server.prebid.org",
   246  			expectedPath:   "/pbcache/endpoint",
   247  		},
   248  		{
   249  			inExtCacheURL: config.ExternalCache{
   250  				Scheme: "",
   251  				Host:   "prebidcache.net",
   252  				Path:   "/",
   253  			},
   254  			expectedScheme: "",
   255  			expectedHost:   "prebidcache.net",
   256  			expectedPath:   "",
   257  		},
   258  	}
   259  	for _, test := range testInput {
   260  		cacheClient := NewClient(&http.Client{}, &inCacheURL, &test.inExtCacheURL, &metricsConf.NilMetricsEngine{})
   261  		scheme, host, path := cacheClient.GetExtCacheData()
   262  
   263  		assert.Equal(t, test.expectedScheme, scheme)
   264  		assert.Equal(t, test.expectedHost, host)
   265  		assert.Equal(t, test.expectedPath, path)
   266  	}
   267  }
   268  
   269  func assertIntEqual(t *testing.T, expected, actual int) {
   270  	t.Helper()
   271  	if expected != actual {
   272  		t.Errorf("Expected %d, got %d", expected, actual)
   273  	}
   274  }
   275  
   276  func assertStringEqual(t *testing.T, expected, actual string) {
   277  	t.Helper()
   278  	if expected != actual {
   279  		t.Errorf(`Expected "%s", got "%s"`, expected, actual)
   280  	}
   281  }
   282  
   283  type handlerResponseObject struct {
   284  	UUID string `json:"uuid"`
   285  }
   286  
   287  type handlerResponse struct {
   288  	Responses []handlerResponseObject `json:"responses"`
   289  }
   290  
   291  func newHandler(numResponses int) http.HandlerFunc {
   292  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   293  		resp := handlerResponse{
   294  			Responses: make([]handlerResponseObject, numResponses),
   295  		}
   296  		for i := 0; i < numResponses; i++ {
   297  			resp.Responses[i].UUID = strconv.Itoa(i)
   298  		}
   299  
   300  		respBytes, _ := json.Marshal(resp)
   301  		w.Write(respBytes)
   302  	})
   303  }