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