Skip to content

Commit

Permalink
Orbidder : bidfloor currency handling (#1714)
Browse files Browse the repository at this point in the history
  • Loading branch information
marki1an authored Feb 9, 2022
1 parent d58c75a commit 7dcc747
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@
import com.iab.openrtb.response.BidResponse;
import com.iab.openrtb.response.SeatBid;
import io.vertx.core.http.HttpMethod;
import org.apache.commons.lang3.StringUtils;
import org.prebid.server.bidder.Bidder;
import org.prebid.server.bidder.model.BidderBid;
import org.prebid.server.bidder.model.BidderError;
import org.prebid.server.bidder.model.HttpCall;
import org.prebid.server.bidder.model.HttpRequest;
import org.prebid.server.bidder.model.Result;
import org.prebid.server.currency.CurrencyConversionService;
import org.prebid.server.exception.PreBidException;
import org.prebid.server.json.DecodeException;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
import org.prebid.server.proto.openrtb.ext.request.orbidder.ExtImpOrbidder;
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.util.BidderUtil;
import org.prebid.server.util.HttpUtil;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -29,15 +33,21 @@

public class OrbidderBidder implements Bidder<BidRequest> {

private static final String BIDDER_CURRENCY = "EUR";
private static final TypeReference<ExtPrebid<?, ExtImpOrbidder>> ORBIDDER_EXT_TYPE_REFERENCE =
new TypeReference<>() {
};

private final String endpointUrl;
private final CurrencyConversionService currencyConversionService;
private final JacksonMapper mapper;

public OrbidderBidder(String endpointUrl, JacksonMapper mapper) {
public OrbidderBidder(String endpointUrl,
CurrencyConversionService currencyConversionService,
JacksonMapper mapper) {

this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
this.currencyConversionService = Objects.requireNonNull(currencyConversionService);
this.mapper = Objects.requireNonNull(mapper);
}

Expand All @@ -48,8 +58,9 @@ public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request

for (Imp imp : request.getImp()) {
try {
final BigDecimal bidFloor = resolveBidFloor(request, imp.getBidfloorcur(), imp.getBidfloor());
parseImpExt(imp);
validImps.add(imp);
validImps.add(modifyImp(imp, bidFloor));
} catch (PreBidException e) {
errors.add(BidderError.badInput(e.getMessage()));
}
Expand All @@ -67,6 +78,23 @@ public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request
errors);
}

private BigDecimal resolveBidFloor(BidRequest bidRequest, String bidfloorcur, BigDecimal bidfloor) {
if (BidderUtil.isValidPrice(bidfloor)
&& !StringUtils.equalsIgnoreCase(bidfloorcur, BIDDER_CURRENCY)
&& StringUtils.isNotBlank(bidfloorcur)) {
return currencyConversionService.convertCurrency(bidfloor, bidRequest, bidfloorcur, BIDDER_CURRENCY);
}

return bidfloor;
}

private static Imp modifyImp(Imp imp, BigDecimal bidFloor) {
return imp.toBuilder()
.bidfloorcur(BIDDER_CURRENCY)
.bidfloor(bidFloor)
.build();
}

private void parseImpExt(Imp imp) {
try {
mapper.mapper().convertValue(imp.getExt(), ORBIDDER_EXT_TYPE_REFERENCE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.prebid.server.bidder.BidderDeps;
import org.prebid.server.bidder.orbidder.OrbidderBidder;
import org.prebid.server.currency.CurrencyConversionService;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties;
import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler;
Expand Down Expand Up @@ -29,13 +30,14 @@ BidderConfigurationProperties configurationProperties() {

@Bean
BidderDeps orbidderBidderDeps(BidderConfigurationProperties orbidderConfigurationProperties,
CurrencyConversionService currencyConversionService,
@NotBlank @Value("${external-url}") String externalUrl,
JacksonMapper mapper) {

return BidderDepsAssembler.forBidder(BIDDER_NAME)
.withConfig(orbidderConfigurationProperties)
.usersyncerCreator(UsersyncerCreator.create(externalUrl))
.bidderCreator(config -> new OrbidderBidder(config.getEndpoint(), mapper))
.bidderCreator(config -> new OrbidderBidder(config.getEndpoint(), currencyConversionService, mapper))
.assemble();
}
}
Original file line number Diff line number Diff line change
@@ -1,41 +1,102 @@
package org.prebid.server.bidder.orbidder;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.iab.openrtb.request.Banner;
import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Imp;
import com.iab.openrtb.response.BidResponse;
import com.iab.openrtb.response.SeatBid;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.prebid.server.VertxTest;
import org.prebid.server.bidder.model.BidderBid;
import org.prebid.server.bidder.model.BidderError;
import org.prebid.server.bidder.model.HttpCall;
import org.prebid.server.bidder.model.HttpRequest;
import org.prebid.server.bidder.model.HttpResponse;
import org.prebid.server.bidder.model.Result;
import org.prebid.server.currency.CurrencyConversionService;
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
import org.prebid.server.proto.openrtb.ext.request.orbidder.ExtImpOrbidder;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.function.UnaryOperator;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.function.UnaryOperator.identity;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.AssertionsForClassTypes.tuple;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;

public class OrbidderBidderTest extends VertxTest {

private static final String ENDPOINT_URL = "https://test.endpoint.com/";

private OrbidderBidder orbidderBidder;

@Rule
public final MockitoRule mockitoRule = MockitoJUnit.rule();

@Mock
private CurrencyConversionService currencyConversionService;

@Before
public void setUp() {
orbidderBidder = new OrbidderBidder(ENDPOINT_URL, jacksonMapper);
orbidderBidder = new OrbidderBidder(ENDPOINT_URL, currencyConversionService, jacksonMapper);
}

@Test
public void creationShouldFailOnInvalidEndpointUrl() {
assertThatIllegalArgumentException().isThrownBy(() -> new OrbidderBidder("invalid_url", jacksonMapper));
assertThatIllegalArgumentException().isThrownBy(
() -> new OrbidderBidder("invalid_url", currencyConversionService, jacksonMapper));
}

@Test
public void makeHttpRequestsShouldReturnProperBidFloorCur() {
// given
final BidRequest bidRequest = givenBidRequest(identity());

// when
final Result<List<HttpRequest<BidRequest>>> result = orbidderBidder.makeHttpRequests(bidRequest);

// then
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue())
.extracting(HttpRequest::getPayload)
.flatExtracting(BidRequest::getImp)
.extracting(Imp::getBidfloorcur)
.containsExactly("EUR");
}

@Test
public void makeHttpRequestsShouldReturnConvertedBidFloorCurrency() {
// given
given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString()))
.willReturn(BigDecimal.ONE);

final BidRequest bidRequest = givenBidRequest(
impBuilder -> impBuilder.bidfloor(BigDecimal.TEN).bidfloorcur("USD"));

// when
final Result<List<HttpRequest<BidRequest>>> result = orbidderBidder.makeHttpRequests(bidRequest);

// then
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue())
.extracting(HttpRequest::getPayload)
.flatExtracting(BidRequest::getImp)
.extracting(Imp::getBidfloor, Imp::getBidfloorcur)
.containsOnly(tuple(BigDecimal.ONE, "EUR"));
}

@Test
Expand Down Expand Up @@ -87,6 +148,28 @@ public void makeBidsShouldReturnErrorsWhenBidsEmptyList()
.containsOnly(Collections.emptyList(), Collections.emptyList());
}

private static BidRequest givenBidRequest(
UnaryOperator<Imp.ImpBuilder> impCustomizer,
UnaryOperator<BidRequest.BidRequestBuilder> requestCustomizer) {
return requestCustomizer.apply(BidRequest.builder()
.imp(singletonList(givenImp(impCustomizer))))
.build();
}

private static BidRequest givenBidRequest(
UnaryOperator<Imp.ImpBuilder> impCustomizer) {
return givenBidRequest(impCustomizer, identity());
}

private static Imp givenImp(UnaryOperator<Imp.ImpBuilder> impCustomizer) {
return impCustomizer.apply(Imp.builder()
.id("123"))
.banner(Banner.builder().build())
.ext(mapper.valueToTree(ExtPrebid.of(null,
ExtImpOrbidder.of("account_id", "placement_id", BigDecimal.ONE))))
.build();
}

private static HttpCall<BidRequest> givenHttpCall(String body) {
return HttpCall.success(
HttpRequest.<BidRequest>builder().payload(null).build(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"h": 250
},
"tagid": "tag_id",
"bidfloorcur": "EUR",
"ext": {
"bidder": {
"accountId": "orbidder-test",
Expand Down

0 comments on commit 7dcc747

Please sign in to comment.