Skip to content

Commit

Permalink
Core: Case Insensitive Check for Bidder Controls (#3352)
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoxaAntoxic authored Aug 12, 2024
1 parent 3017465 commit af6fcb4
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Imp;
import org.apache.commons.lang3.StringUtils;
import org.prebid.server.auction.BidderAliases;
import org.prebid.server.bidder.BidderCatalog;
import org.prebid.server.bidder.model.BidderError;
Expand All @@ -14,6 +15,7 @@

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -78,10 +80,11 @@ private MediaType preferredMediaType(BidRequest bidRequest,
Account account,
String originalBidderName,
String resolvedBidderName) {

return Optional.ofNullable(bidRequest.getExt())
.map(ExtRequest::getPrebid)
.map(ExtRequestPrebid::getBiddercontrols)
.map(bidders -> bidders.get(originalBidderName))
.map(bidders -> getBidder(originalBidderName, bidders))
.map(bidder -> bidder.get(PREF_MTYPE_FIELD))
.filter(JsonNode::isTextual)
.map(JsonNode::textValue)
Expand All @@ -92,6 +95,17 @@ private MediaType preferredMediaType(BidRequest bidRequest,
.orElse(null);
}

private static JsonNode getBidder(String bidderName, JsonNode biddersNode) {
final Iterator<String> fieldNames = biddersNode.fieldNames();
while (fieldNames.hasNext()) {
final String fieldName = fieldNames.next();
if (StringUtils.equalsIgnoreCase(bidderName, fieldName)) {
return biddersNode.get(fieldName);
}
}
return null;
}

private static Imp processImp(Imp imp, MediaType preferredMediaType, List<BidderError> errors) {
if (!isMultiFormat(imp)) {
return imp;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package org.prebid.server.functional.model.request.auction

import com.fasterxml.jackson.annotation.JsonProperty
import groovy.transform.ToString

@ToString(includeNames = true, ignoreNulls = true)
class BidderControls {

GenericPreferredBidder generic
@JsonProperty("GeNeRiC")
GenericPreferredBidder genericAnyCase
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.prebid.server.functional.tests

import org.prebid.server.functional.model.bidder.BidderName
import org.prebid.server.functional.model.bidder.Generic
import org.prebid.server.functional.model.config.AccountAuctionConfig
import org.prebid.server.functional.model.config.AccountConfig
import org.prebid.server.functional.model.db.Account
Expand All @@ -11,6 +12,7 @@ import org.prebid.server.functional.model.request.auction.BidderControls
import org.prebid.server.functional.model.request.auction.GenericPreferredBidder
import org.prebid.server.functional.model.request.auction.Native

import static org.prebid.server.functional.model.bidder.BidderName.ALIAS
import static org.prebid.server.functional.model.response.auction.ErrorType.GENERIC
import static org.prebid.server.functional.model.response.auction.MediaType.AUDIO
import static org.prebid.server.functional.model.response.auction.MediaType.BANNER
Expand Down Expand Up @@ -52,7 +54,7 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].banner = Banner.defaultBanner
imp[0].audio = Audio.defaultAudio
ext.prebid.bidderControls = new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER))
ext.prebid.bidderControls = bidderControls
}

when: "PBS processes auction request"
Expand All @@ -62,6 +64,12 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp[0].banner
assert bidderRequest.imp[0].audio

where:
bidderControls << [
new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER)),
new BidderControls(genericAnyCase: new GenericPreferredBidder(preferredMediaType: BANNER))
]
}

def "PBS should respond with one requested preferred media type when default adapters multi format is false in config and preferred media type specified at account level"() {
Expand Down Expand Up @@ -98,7 +106,7 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].banner = Banner.defaultBanner
imp[0].audio = Audio.defaultAudio
ext.prebid.bidderControls = new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER))
ext.prebid.bidderControls = bidderControls
}

when: "PBS processes auction request"
Expand All @@ -108,6 +116,12 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp[0].banner
assert !bidderRequest.imp[0].audio

where:
bidderControls << [
new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER)),
new BidderControls(genericAnyCase: new GenericPreferredBidder(preferredMediaType: BANNER))
]
}

def "PBS should respond with all requested media type when multi format is true in config and preferred media type specified at request level"() {
Expand All @@ -119,7 +133,7 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].banner = Banner.defaultBanner
imp[0].audio = Audio.defaultAudio
ext.prebid.bidderControls = new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER))
ext.prebid.bidderControls = bidderControls
}

when: "PBS processes auction request"
Expand All @@ -129,6 +143,12 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp.banner
assert bidderRequest.imp.audio

where:
bidderControls << [
new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER)),
new BidderControls(genericAnyCase: new GenericPreferredBidder(preferredMediaType: BANNER))
]
}

def "PBS should respond with all requested media type when multi format is true in config and preferred media type specified at account level"() {
Expand Down Expand Up @@ -190,7 +210,7 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].banner = Banner.defaultBanner
imp[0].audio = Audio.defaultAudio
ext.prebid.bidderControls = new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER))
ext.prebid.bidderControls = bidderControls
}

when: "PBS processes auction request"
Expand All @@ -200,6 +220,12 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp[0].banner
assert !bidderRequest.imp[0].audio

where:
bidderControls << [
new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER)),
new BidderControls(genericAnyCase: new GenericPreferredBidder(preferredMediaType: BANNER))
]
}

def "PBS should respond with warning and don't make a bidder call when multi format at request and preferred media type specified at account level with non requested media type"() {
Expand Down Expand Up @@ -241,7 +267,7 @@ class FilterMultiFormatSpec extends BaseSpec {
imp[0].banner = null
imp[0].audio = Audio.defaultAudio
imp[0].nativeObj = Native.defaultNative
ext.prebid.bidderControls = new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER))
ext.prebid.bidderControls = bidderControls
}

when: "PBS processes auction request"
Expand All @@ -254,6 +280,12 @@ class FilterMultiFormatSpec extends BaseSpec {
assert bidResponse.ext.warnings[GENERIC]?.message ==
["Imp ${bidRequest.imp[0].id} does not have a media type after filtering and has been removed from the request for this bidder.",
"Bid request contains 0 impressions after filtering."]

where:
bidderControls << [
new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER)),
new BidderControls(genericAnyCase: new GenericPreferredBidder(preferredMediaType: BANNER))
]
}

def "PBS shouldn't respond with warning and make a bidder call when request doesn't contain multi format and preferred media type specified at account level"() {
Expand Down Expand Up @@ -292,7 +324,7 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].banner = null
imp[0].audio = Audio.defaultAudio
ext.prebid.bidderControls = new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER))
ext.prebid.bidderControls = bidderControls
}

when: "PBS processes auction request"
Expand All @@ -304,6 +336,12 @@ class FilterMultiFormatSpec extends BaseSpec {

and: "Bid response shouldn't contain warning"
assert !bidResponse.ext.warnings

where:
bidderControls << [
new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER)),
new BidderControls(genericAnyCase: new GenericPreferredBidder(preferredMediaType: BANNER))
]
}

def "PBS shouldn't respond with warning and make a bidder call when request doesn't contain multi format and multi format is false and preferred media type specified at request level with null"() {
Expand All @@ -315,7 +353,7 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].banner = Banner.getDefaultBanner()
imp[0].audio = Audio.defaultAudio
ext.prebid.bidderControls = new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: NULL))
ext.prebid.bidderControls = bidderControls
}

when: "PBS processes auction request"
Expand All @@ -326,6 +364,12 @@ class FilterMultiFormatSpec extends BaseSpec {

and: "Bid response shouldn't contain warning"
assert !bidResponse.ext?.warnings

where:
bidderControls << [
new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: NULL)),
new BidderControls(genericAnyCase: new GenericPreferredBidder(preferredMediaType: NULL)),
]
}

def "PBS shouldn't respond with warning and make a bidder call when request doesn't contain multi format and multi format is false and preferred media type specified at account level with null"() {
Expand Down Expand Up @@ -364,7 +408,7 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].banner = Banner.defaultBanner
imp[0].audio = Audio.defaultAudio
ext.prebid.bidderControls = new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER))
ext.prebid.bidderControls = bidderControls
}

and: "Account in the DB with preferred media type"
Expand All @@ -379,5 +423,53 @@ class FilterMultiFormatSpec extends BaseSpec {
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp[0].banner
assert !bidderRequest.imp[0].audio

where:
bidderControls << [
new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER)),
new BidderControls(genericAnyCase: new GenericPreferredBidder(preferredMediaType: BANNER))
]
}

def "PBS should not preferred media type specified at request level when it's alias bidder"() {
given: "PBS with adapter configuration"
def pbsService = pbsServiceFactory.getService(
"adapter-defaults.ortb.multiformat-supported": "false",
"adapters.generic.ortb.multiformat-supported": "false")

and: "Default bid request with alias"
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].tap {
banner = Banner.defaultBanner
audio = Audio.defaultAudio
ext.prebid.bidder.tap {
alias = new Generic()
generic = null
}
}
ext.prebid.tap {
it.aliases = [(ALIAS.value): BidderName.GENERIC]
it.bidderControls = bidderControls
}
}

and: "Account in the DB with preferred media type"
def accountConfig = new AccountAuctionConfig(preferredMediaType: [(BidderName.GENERIC): AUDIO])
def account = new Account(uuid: bidRequest.accountId, config: new AccountConfig(auction: accountConfig))
accountDao.save(account)

when: "PBS processes auction request"
pbsService.sendAuctionRequest(bidRequest)

then: "Bidder request should contain preferred media type from account config"
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert !bidderRequest.imp[0].banner
assert bidderRequest.imp[0].audio

where:
bidderControls << [
new BidderControls(generic: new GenericPreferredBidder(preferredMediaType: BANNER)),
new BidderControls(genericAnyCase: new GenericPreferredBidder(preferredMediaType: BANNER))
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,40 @@ public void processShouldUseRequestLevelPreferredMediaTypeFirst() {
assertThat(result.getErrors()).isEmpty();
}

@Test
public void processShouldUseRequestLevelPreferredMediaTypeFirstCaseInsensitive() {
// given
given(bidderAliases.resolveBidder(BIDDER)).willReturn("resolvedBidderName");
given(bidderCatalog.bidderInfoByName("resolvedBidderName")).willReturn(givenBidderInfo(false));

final ObjectNode bidderControls = mapper.createObjectNode();
bidderControls.putObject(BIDDER.toUpperCase()).put("prefmtype", "video");

final BidRequest bidRequest = givenBidRequest(
request -> request.ext(ExtRequest.of(ExtRequestPrebid.builder()
.biddercontrols(bidderControls)
.build())),
givenImp(BANNER, VIDEO, AUDIO, NATIVE));

final Account account = givenAccount(Map.of("resolvedBidderName", AUDIO));

// when
final MediaTypeProcessingResult result = target.process(bidRequest, BIDDER, bidderAliases, account);

// then
assertThat(result.isRejected()).isFalse();
assertThat(result.getBidRequest())
.extracting(BidRequest::getImp)
.asInstanceOf(InstanceOfAssertFactories.list(Imp.class))
.containsExactly(givenImp(VIDEO));
assertThat(result.getBidRequest())
.extracting(BidRequest::getExt)
.extracting(ExtRequest::getPrebid)
.extracting(ExtRequestPrebid::getBiddercontrols)
.isNull();
assertThat(result.getErrors()).isEmpty();
}

@Test
public void processShouldSkipImpsWithSingleMediaType() {
// given
Expand Down

0 comments on commit af6fcb4

Please sign in to comment.