github.com/prebid/prebid-server/v2@v2.18.0/adservertargeting/requestlookup_test.go (about) 1 package adservertargeting 2 3 import ( 4 "encoding/json" 5 "net/url" 6 "testing" 7 8 "github.com/prebid/openrtb/v20/openrtb2" 9 "github.com/prebid/prebid-server/v2/openrtb_ext" 10 "github.com/stretchr/testify/assert" 11 ) 12 13 func TestGetAdServerTargeting(t *testing.T) { 14 15 testCases := []struct { 16 description string 17 inputRequestExt json.RawMessage 18 expectedTargeting []openrtb_ext.AdServerTarget 19 expectedError bool 20 }{ 21 { 22 description: "valid request with no ext.prebid", 23 inputRequestExt: json.RawMessage(``), 24 expectedTargeting: nil, 25 expectedError: false, 26 }, 27 { 28 description: "valid request with correct ext.prebid, no ad server targeting", 29 inputRequestExt: json.RawMessage(`{"prebid":{}}`), 30 expectedTargeting: nil, 31 expectedError: false, 32 }, 33 { 34 description: "valid request with correct ext.prebid, and empty ad server targeting", 35 inputRequestExt: json.RawMessage(`{"prebid":{"adservertargeting":[]}}`), 36 expectedTargeting: []openrtb_ext.AdServerTarget{}, 37 expectedError: false, 38 }, 39 { 40 description: "valid request with correct ext.prebid, and with ad server targeting", 41 inputRequestExt: json.RawMessage(`{"prebid":{"adservertargeting":[ 42 {"key": "adt_key", 43 "source": "bidrequest", 44 "value": "ext.prebid.data"} 45 ]}}`), 46 expectedTargeting: []openrtb_ext.AdServerTarget{ 47 {Key: "adt_key", Source: "bidrequest", Value: "ext.prebid.data"}, 48 }, 49 expectedError: false, 50 }, 51 } 52 53 for _, test := range testCases { 54 request := &openrtb_ext.RequestWrapper{ 55 BidRequest: &openrtb2.BidRequest{ID: "req_id", Ext: test.inputRequestExt}, 56 } 57 58 actualTargeting, err := getAdServerTargeting(request) 59 60 assert.Equal(t, test.expectedTargeting, actualTargeting, "targeting data doesn't match") 61 if test.expectedError { 62 assert.Error(t, err, "expected error not returned") 63 } else { 64 assert.NoError(t, err, "unexpected error returned") 65 } 66 } 67 } 68 69 func TestValidateAdServerTargeting(t *testing.T) { 70 testCases := []struct { 71 description string 72 inputTargeting []openrtb_ext.AdServerTarget 73 expectedTargeting []openrtb_ext.AdServerTarget 74 expectedWarnings []openrtb_ext.ExtBidderMessage 75 }{ 76 { 77 description: "valid targeting object", 78 inputTargeting: []openrtb_ext.AdServerTarget{ 79 {Key: "adt_key", Source: "bidrequest", Value: "ext.prebid.data"}, 80 }, 81 expectedTargeting: []openrtb_ext.AdServerTarget{ 82 {Key: "adt_key", Source: "bidrequest", Value: "ext.prebid.data"}, 83 }, 84 expectedWarnings: []openrtb_ext.ExtBidderMessage(nil), 85 }, 86 { 87 description: "invalid targeting object: key", 88 inputTargeting: []openrtb_ext.AdServerTarget{ 89 {Key: "", Source: "bidrequest", Value: "ext.prebid.data"}, 90 }, 91 expectedTargeting: []openrtb_ext.AdServerTarget(nil), 92 expectedWarnings: []openrtb_ext.ExtBidderMessage{ 93 {Code: 10007, Message: "Key is empty for the ad server targeting object at index 0"}, 94 }, 95 }, 96 { 97 description: "invalid targeting object: source", 98 inputTargeting: []openrtb_ext.AdServerTarget{ 99 {Key: "adt_key", Source: "incorrect", Value: "ext.prebid.data"}, 100 }, 101 expectedTargeting: []openrtb_ext.AdServerTarget(nil), 102 expectedWarnings: []openrtb_ext.ExtBidderMessage{ 103 {Code: 10007, Message: "Incorrect source for the ad server targeting object at index 0"}, 104 }, 105 }, 106 { 107 description: "invalid targeting object: value", 108 inputTargeting: []openrtb_ext.AdServerTarget{ 109 {Key: "adt_key", Source: "static", Value: ""}, 110 }, 111 expectedTargeting: []openrtb_ext.AdServerTarget(nil), 112 expectedWarnings: []openrtb_ext.ExtBidderMessage{ 113 {Code: 10007, Message: "Value is empty for the ad server targeting object at index 0"}, 114 }, 115 }, 116 { 117 description: "valid and invalid targeting object", 118 inputTargeting: []openrtb_ext.AdServerTarget{ 119 {Key: "adt_key1", Source: "static", Value: "valid"}, 120 {Key: "adt_key2", Source: "static", Value: ""}, 121 }, 122 expectedTargeting: []openrtb_ext.AdServerTarget{ 123 {Key: "adt_key1", Source: "static", Value: "valid"}, 124 }, 125 expectedWarnings: []openrtb_ext.ExtBidderMessage{ 126 {Code: 10007, Message: "Value is empty for the ad server targeting object at index 1"}, 127 }, 128 }, 129 } 130 131 for _, test := range testCases { 132 actualTargeting, actualWarnings := validateAdServerTargeting(test.inputTargeting) 133 assert.Equal(t, test.expectedTargeting, actualTargeting, "incorrect targeting data") 134 assert.Equal(t, test.expectedWarnings, actualWarnings, "incorrect warnings") 135 } 136 } 137 138 func TestGetValueFromBidRequest(t *testing.T) { 139 140 testCases := []struct { 141 description string 142 inputPath string 143 expectedTargeting RequestTargetingData 144 expectedError bool 145 }{ 146 { 147 description: "get existing value from query params", 148 inputPath: "ext.prebid.amp.data.amp-key", 149 expectedTargeting: RequestTargetingData{SingleVal: json.RawMessage(`testAmpKey`)}, 150 expectedError: false, 151 }, 152 { 153 description: "get non-existing value from query params", 154 inputPath: "ext.prebid.amp.data.amp-key-not-existing", 155 expectedTargeting: RequestTargetingData{}, 156 expectedError: true, 157 }, 158 { 159 description: "get existing value from impressions", 160 inputPath: "imp.banner.h", 161 expectedTargeting: RequestTargetingData{ 162 TargetingValueByImpId: map[string][]byte{ 163 "test_imp1": []byte(`350`), 164 "test_imp2": []byte(`360`), 165 }, 166 }, 167 expectedError: false, 168 }, 169 { 170 description: "get existing value from impressions ext", 171 inputPath: "imp.ext.appnexus.placementId", 172 expectedTargeting: RequestTargetingData{ 173 TargetingValueByImpId: map[string][]byte{ 174 "test_imp1": []byte(`123`), 175 "test_imp2": []byte(`456`), 176 }, 177 }, 178 expectedError: false, 179 }, 180 { 181 description: "get non-existing value from impressions", 182 inputPath: "imp.video", 183 expectedTargeting: RequestTargetingData{}, 184 expectedError: true, 185 }, 186 { 187 description: "get existing value from req", 188 inputPath: "site.page", 189 expectedTargeting: RequestTargetingData{ 190 SingleVal: json.RawMessage(`test.com`), 191 }, 192 expectedError: false, 193 }, 194 { 195 description: "get non-existing value from req", 196 inputPath: "app", 197 expectedTargeting: RequestTargetingData{}, 198 expectedError: true, 199 }, 200 } 201 202 reqCache := requestCache{ 203 resolvedReq: json.RawMessage(reqFullValid), 204 } 205 206 u, _ := url.Parse(testUrl) 207 params := u.Query() 208 209 for _, test := range testCases { 210 resTargetingData, err := getValueFromBidRequest(&reqCache, test.inputPath, params) 211 212 assert.Equal(t, test.expectedTargeting, resTargetingData, "incorrect targeting data returned") 213 214 if test.expectedError { 215 assert.Error(t, err, "expected error not returned") 216 } else { 217 assert.NoError(t, err, "unexpected error returned") 218 } 219 } 220 } 221 222 func TestGetValueFromQueryParam(t *testing.T) { 223 u, _ := url.Parse(testUrl) 224 params := u.Query() 225 226 testCases := []struct { 227 description string 228 inputPath string 229 expectedValue json.RawMessage 230 expectedError bool 231 }{ 232 { 233 description: "get existing value from query params", 234 inputPath: "ext.prebid.amp.data.amp-key", 235 expectedValue: json.RawMessage(`testAmpKey`), 236 expectedError: false, 237 }, 238 { 239 description: "get non-existing value from query params", 240 inputPath: "ext.prebid.amp.data.amp-key-not-existing", 241 expectedValue: nil, 242 expectedError: true, 243 }, 244 { 245 description: "get value from not query params path", 246 inputPath: "ext.data.amp-key-not-existing", 247 expectedValue: nil, 248 expectedError: false, 249 }, 250 } 251 252 for _, test := range testCases { 253 res, err := getValueFromQueryParam(test.inputPath, params) 254 255 assert.Equal(t, test.expectedValue, res, "incorrect value found") 256 if test.expectedError { 257 assert.Error(t, err, "expected error not returned") 258 } else { 259 assert.NoError(t, err, "unexpected error returned") 260 } 261 } 262 } 263 264 func TestGetValueFromImp(t *testing.T) { 265 266 testCases := []struct { 267 description string 268 inputPath string 269 inputRequest json.RawMessage 270 expectedTargeting map[string][]byte 271 expectedError bool 272 }{ 273 274 { 275 description: "get existing value from impressions", 276 inputPath: "imp.banner.h", 277 inputRequest: json.RawMessage(reqFullValid), 278 expectedTargeting: map[string][]byte{ 279 "test_imp1": []byte(`350`), 280 "test_imp2": []byte(`360`), 281 }, 282 expectedError: false, 283 }, 284 { 285 description: "get existing value from impressions ext", 286 inputPath: "imp.ext.appnexus.placementId", 287 expectedTargeting: map[string][]byte{ 288 "test_imp1": []byte(`123`), 289 "test_imp2": []byte(`456`), 290 }, 291 inputRequest: json.RawMessage(reqFullValid), 292 expectedError: false, 293 }, 294 { 295 description: "get non-existing value from impressions", 296 inputPath: "imp.video", 297 expectedTargeting: map[string][]byte(nil), 298 inputRequest: json.RawMessage(reqFullValid), 299 expectedError: true, 300 }, 301 { 302 description: "get value from invalid impressions", 303 inputPath: "imp.video", 304 expectedTargeting: map[string][]byte(nil), 305 inputRequest: json.RawMessage(reqFullInvalid), 306 expectedError: true, 307 }, 308 { 309 description: "get value from request without impressions", 310 inputPath: "imp.video", 311 expectedTargeting: map[string][]byte(nil), 312 inputRequest: json.RawMessage(`{}`), 313 expectedError: true, 314 }, 315 } 316 317 for _, test := range testCases { 318 319 reqCache := requestCache{ 320 resolvedReq: test.inputRequest, 321 } 322 323 resData, err := getValueFromImp(test.inputPath, &reqCache) 324 325 assert.Equal(t, test.expectedTargeting, resData, "incorrect imp data returned") 326 327 if test.expectedError { 328 assert.Error(t, err, "expected error not returned") 329 } else { 330 assert.NoError(t, err, "unexpected error returned") 331 } 332 } 333 } 334 335 func TestGetValueFromRequestJson(t *testing.T) { 336 337 testCases := []struct { 338 description string 339 inputPath string 340 expectedValue json.RawMessage 341 expectedError bool 342 }{ 343 344 { 345 description: "get existing value from req", 346 inputPath: "site.page", 347 expectedValue: json.RawMessage(`test.com`), 348 expectedError: false, 349 }, 350 { 351 description: "get non-existing value from req", 352 inputPath: "app", 353 expectedValue: json.RawMessage(nil), 354 expectedError: true, 355 }, 356 } 357 358 reqCache := requestCache{ 359 resolvedReq: json.RawMessage(reqFullValid), 360 } 361 362 for _, test := range testCases { 363 resValue, err := getDataFromRequestJson(test.inputPath, &reqCache) 364 365 assert.Equal(t, test.expectedValue, resValue, "incorrect request data returned") 366 367 if test.expectedError { 368 assert.Error(t, err, "expected error not returned") 369 } else { 370 assert.NoError(t, err, "unexpected error returned") 371 } 372 } 373 }