Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Greenbids: Add account level config for modules RTD, analytics #3596

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
@Value(staticConstructor = "of")
public class Partner {

@JsonProperty(required = true)
Boolean enabled;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure you need this particular flag, because it's possible to enable/disable the module using execution plan or hooks.admin.module-execution properties on the account or host-level config and the core skips execution of the module for you


String pbuid;

@JsonProperty("targetTpr")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.prebid.server.hooks.modules.greenbids.real.time.data.v1;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iab.openrtb.request.BidRequest;
Expand Down Expand Up @@ -33,8 +32,8 @@
import org.prebid.server.hooks.v1.auction.AuctionInvocationContext;
import org.prebid.server.hooks.v1.auction.AuctionRequestPayload;
import org.prebid.server.hooks.v1.auction.ProcessedAuctionRequestHook;
import org.prebid.server.proto.openrtb.ext.request.ExtRequest;
import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid;
import org.prebid.server.settings.model.Account;
import org.prebid.server.settings.model.AccountHooksConfiguration;

import java.util.Collections;
import java.util.List;
Expand All @@ -47,7 +46,6 @@ public class GreenbidsRealTimeDataProcessedAuctionRequestHook implements Process
private static final String CODE = "greenbids-real-time-data-processed-auction-request";
private static final String ACTIVITY = "greenbids-filter";
private static final String SUCCESS_STATUS = "success";
private static final String BID_REQUEST_ANALYTICS_EXTENSION_NAME = "greenbids-rtd";

private final ObjectMapper mapper;
private final FilterService filterService;
Expand Down Expand Up @@ -75,38 +73,39 @@ public Future<InvocationResult<AuctionRequestPayload>> call(

final AuctionContext auctionContext = invocationContext.auctionContext();
final BidRequest bidRequest = auctionContext.getBidRequest();
final Partner partner = parseBidRequestExt(bidRequest);
final Partner appliedPartner = parseAccountConfig(auctionContext);

if (partner == null) {
if (!appliedPartner.getEnabled()) {
return Future.succeededFuture(toInvocationResult(
bidRequest, null, InvocationAction.no_action));
}

return Future.all(
onnxModelRunnerWithThresholds.retrieveOnnxModelRunner(partner),
onnxModelRunnerWithThresholds.retrieveThreshold(partner))
onnxModelRunnerWithThresholds.retrieveOnnxModelRunner(appliedPartner),
onnxModelRunnerWithThresholds.retrieveThreshold(appliedPartner))
.compose(compositeFuture -> toInvocationResult(
bidRequest,
partner,
appliedPartner,
compositeFuture.resultAt(0),
compositeFuture.resultAt(1)))
.recover(throwable -> Future.succeededFuture(toInvocationResult(
bidRequest, null, InvocationAction.no_action)));
}

private Partner parseBidRequestExt(BidRequest bidRequest) {
return Optional.ofNullable(bidRequest)
.map(BidRequest::getExt)
.map(ExtRequest::getPrebid)
.map(ExtRequestPrebid::getAnalytics)
.filter(this::isNotEmptyObjectNode)
.map(analytics -> (ObjectNode) analytics.get(BID_REQUEST_ANALYTICS_EXTENSION_NAME))
.map(this::toPartner)
private Partner parseAccountConfig(AuctionContext auctionContext) {
final Map<String, ObjectNode> modules = Optional.ofNullable(auctionContext)
.map(AuctionContext::getAccount)
.map(Account::getHooks)
.map(AccountHooksConfiguration::getModules)
.orElse(null);
}

private boolean isNotEmptyObjectNode(JsonNode analytics) {
return analytics != null && analytics.isObject() && !analytics.isEmpty();
Partner partner = null;
if (modules != null && modules.containsKey("greenbids")) {
final ObjectNode moduleConfig = modules.get("greenbids");
partner = toPartner(moduleConfig);
}

return partner;
Comment on lines +95 to +108
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can skip this parsing, and just call toPartner(invocationContext.accountConfig()) and you'll get what you need (of course some null checks and json parsing exception should be handled)

also if the Partner is considered to be a representation of the account config, I suggest rename it to the Config or GreenbidsConfig (something like that)

}

private Partner toPartner(ObjectNode adapterNode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void extractThrottlingMessagesFromBidRequestShouldReturnValidThrottlingMe
.banner(banner)
.build();
final Device device = givenDevice(identity());
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device, null);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device);

final CountryResponse countryResponse = mock(CountryResponse.class);

Expand Down Expand Up @@ -110,7 +110,7 @@ public void extractThrottlingMessagesFromBidRequestShouldHandleMissingIp() {
.banner(banner)
.build();
final Device device = givenDeviceWithoutIp(identity());
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device, null);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device);

final ZonedDateTime timestamp = ZonedDateTime.now(ZoneId.of("UTC"));
final Integer expectedHourBucket = timestamp.getHour();
Expand Down Expand Up @@ -147,7 +147,7 @@ public void extractThrottlingMessagesFromBidRequestShouldThrowPreBidExceptionWhe
.banner(banner)
.build();
final Device device = givenDevice(identity());
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device, null);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device);

when(databaseReader.country(any(InetAddress.class))).thenThrow(new GeoIp2Exception("GeoIP failure"));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void createGreenbidsInvocationResultShouldReturnUpdateBidRequestWhenNotEx
.banner(banner)
.build();
final Device device = givenDevice(identity());
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device, null);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device);
final Map<String, Map<String, Boolean>> impsBiddersFilterMap = givenImpsBiddersFilterMap();
final Partner partner = givenPartner(0.0);

Expand Down Expand Up @@ -82,7 +82,7 @@ public void createGreenbidsInvocationResultShouldReturnNoActionWhenExploration()
.banner(banner)
.build();
final Device device = givenDevice(identity());
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device, null);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device);
final Map<String, Map<String, Boolean>> impsBiddersFilterMap = givenImpsBiddersFilterMap();
final Partner partner = givenPartner(1.0);

Expand Down Expand Up @@ -121,6 +121,6 @@ private Map<String, Map<String, Boolean>> givenImpsBiddersFilterMap() {
}

private Partner givenPartner(Double explorationRate) {
return Partner.of("test-pbuid", 0.60, explorationRate);
return Partner.of(true, "test-pbuid", 0.60, explorationRate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.iab.openrtb.request.Imp;
import com.iab.openrtb.request.Site;
import org.prebid.server.json.ObjectMapperProvider;
import org.prebid.server.proto.openrtb.ext.request.ExtRequest;

import java.util.Collections;
import java.util.List;
Expand All @@ -25,15 +24,13 @@ private TestBidRequestProvider() { }
public static BidRequest givenBidRequest(
UnaryOperator<BidRequest.BidRequestBuilder> bidRequestCustomizer,
List<Imp> imps,
Device device,
ExtRequest extRequest) {
Device device) {

return bidRequestCustomizer.apply(BidRequest.builder()
.id("request")
.imp(imps)
.site(givenSite(site -> site))
.device(device)
.ext(extRequest)).build();
.device(device)).build();
}

public static Site givenSite(UnaryOperator<Site.SiteBuilder> siteCustomizer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
import org.prebid.server.hooks.v1.auction.AuctionInvocationContext;
import org.prebid.server.hooks.v1.auction.AuctionRequestPayload;
import org.prebid.server.model.HttpRequestContext;
import org.prebid.server.proto.openrtb.ext.request.ExtRequest;
import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid;
import org.prebid.server.settings.model.Account;
import org.prebid.server.settings.model.AccountHooksConfiguration;

import java.io.FileOutputStream;
import java.io.IOException;
Expand Down Expand Up @@ -129,7 +129,8 @@ public void setUp() throws IOException {
}

@Test
public void callShouldExitEarlyWhenPartnerNotActivatedInBidRequest() {
public void callShouldFilterBiddersAndFallbackToAccountLevelConfigWhenPartnerNotActivatedInBidRequest()
throws IOException, OrtException {
// given
final Banner banner = givenBanner();

Expand All @@ -139,24 +140,54 @@ public void callShouldExitEarlyWhenPartnerNotActivatedInBidRequest() {
.banner(banner)
.build();

final Double explorationRate = 0.0001;
final Device device = givenDevice(identity());
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device, null);
final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device);
final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context, explorationRate);
final AuctionInvocationContext invocationContext = givenAuctionInvocationContext(auctionContext);
when(invocationContext.auctionContext()).thenReturn(auctionContext);
when(modelCacheWithExpiration.getIfPresent("onnxModelRunner_test-pbuid"))
.thenReturn(givenOnnxModelRunner());
when(thresholdsCacheWithExpiration.getIfPresent("throttlingThresholds_test-pbuid"))
.thenReturn(givenThrottlingThresholds());

final BidRequest expectedBidRequest = expectedUpdatedBidRequest(
request -> request, device);
final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false);

// when
final Future<InvocationResult<AuctionRequestPayload>> future = target
.call(null, invocationContext);
final InvocationResult<AuctionRequestPayload> result = future.result();
final BidRequest resultBidRequest = result
.payloadUpdate()
.apply(AuctionRequestPayloadImpl.of(bidRequest))
.bidRequest();

// then
final ActivityImpl activityImpl = (ActivityImpl) result.analyticsTags().activities().getFirst();
final ResultImpl resultImpl = (ResultImpl) activityImpl.results().getFirst();
final String fingerprint = resultImpl.values()
.get("adunitcodevalue")
.get("greenbids")
.get("fingerprint").asText();

assertThat(future).isNotNull();
assertThat(future.succeeded()).isTrue();
assertThat(result).isNotNull();
assertThat(result.status()).isEqualTo(InvocationStatus.success);
assertThat(result.action()).isEqualTo(InvocationAction.no_action);
assertThat(result.analyticsTags()).isNull();
assertThat(result.action()).isEqualTo(InvocationAction.update);
assertThat(result.analyticsTags()).isNotNull();
assertThat(result.analyticsTags()).usingRecursiveComparison()
.ignoringFields(
"activities.results"
+ ".values._children"
+ ".adunitcodevalue._children"
+ ".greenbids._children.fingerprint")
.isEqualTo(toAnalyticsTags(List.of(expectedAnalyticsResult))); // NOK
assertThat(fingerprint).isNotNull();
assertThat(resultBidRequest).usingRecursiveComparison()
.isEqualTo(expectedBidRequest);
}

@Test
Expand All @@ -172,9 +203,8 @@ public void callShouldNotFilterBiddersAndReturnAnalyticsTagWhenExploration() thr

final Double explorationRate = 1.0;
final Device device = givenDevice(identity());
final ExtRequest extRequest = givenExtRequest(explorationRate);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device, extRequest);
final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device);
final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context, explorationRate);
final AuctionInvocationContext invocationContext = givenAuctionInvocationContext(auctionContext);
when(invocationContext.auctionContext()).thenReturn(auctionContext);
when(modelCacheWithExpiration.getIfPresent("onnxModelRunner_test-pbuid"))
Expand Down Expand Up @@ -226,17 +256,17 @@ public void callShouldFilterBiddersBasedOnModelWhenAnyFeatureNotAvailable() thro

final Double explorationRate = 0.0001;
final Device device = givenDeviceWithoutUserAgent(identity());
final ExtRequest extRequest = givenExtRequest(explorationRate);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device, extRequest);
final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device);
final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context, explorationRate);
final AuctionInvocationContext invocationContext = givenAuctionInvocationContext(auctionContext);
when(invocationContext.auctionContext()).thenReturn(auctionContext);
when(modelCacheWithExpiration.getIfPresent("onnxModelRunner_test-pbuid"))
.thenReturn(givenOnnxModelRunner());
when(thresholdsCacheWithExpiration.getIfPresent("throttlingThresholds_test-pbuid"))
.thenReturn(givenThrottlingThresholds());

final BidRequest expectedBidRequest = expectedUpdatedBidRequest(request -> request, explorationRate, device);
final BidRequest expectedBidRequest = expectedUpdatedBidRequest(
request -> request, device);
final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false);

// when
Expand Down Expand Up @@ -286,9 +316,8 @@ public void callShouldFilterBiddersBasedOnModelResults() throws OrtException, IO

final Double explorationRate = 0.0001;
final Device device = givenDevice(identity());
final ExtRequest extRequest = givenExtRequest(explorationRate);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device, extRequest);
final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context);
final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device);
final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context, explorationRate);
final AuctionInvocationContext invocationContext = givenAuctionInvocationContext(auctionContext);
when(invocationContext.auctionContext()).thenReturn(auctionContext);
when(modelCacheWithExpiration.getIfPresent("onnxModelRunner_test-pbuid"))
Expand All @@ -297,7 +326,7 @@ public void callShouldFilterBiddersBasedOnModelResults() throws OrtException, IO
.thenReturn(givenThrottlingThresholds());

final BidRequest expectedBidRequest = expectedUpdatedBidRequest(
request -> request, explorationRate, device);
request -> request, device);
final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false);

// when
Expand Down Expand Up @@ -348,28 +377,15 @@ static DatabaseReader givenDatabaseReader() throws IOException {
return new DatabaseReader.Builder(databasePath.toFile()).build();
}

static ExtRequest givenExtRequest(Double explorationRate) {
final ObjectNode greenbidsNode = TestBidRequestProvider.MAPPER.createObjectNode();
greenbidsNode.put("pbuid", "test-pbuid");
greenbidsNode.put("targetTpr", 0.60);
greenbidsNode.put("explorationRate", explorationRate);

final ObjectNode analyticsNode = TestBidRequestProvider.MAPPER.createObjectNode();
analyticsNode.set("greenbids-rtd", greenbidsNode);

return ExtRequest.of(ExtRequestPrebid
.builder()
.analytics(analyticsNode)
.build());
}

private AuctionContext givenAuctionContext(
BidRequest bidRequest,
UnaryOperator<AuctionContext.AuctionContextBuilder> auctionContextCustomizer) {
UnaryOperator<AuctionContext.AuctionContextBuilder> auctionContextCustomizer,
Double explorationRate) {

final AuctionContext.AuctionContextBuilder auctionContextBuilder = AuctionContext.builder()
.httpRequest(HttpRequestContext.builder().build())
.bidRequest(bidRequest);
.bidRequest(bidRequest)
.account(givenAccount(explorationRate));

return auctionContextCustomizer.apply(auctionContextBuilder).build();
}
Expand All @@ -380,6 +396,23 @@ private AuctionInvocationContext givenAuctionInvocationContext(AuctionContext au
return invocationContext;
}

private Account givenAccount(Double explorationRate) {
return Account.builder()
.id("test-account")
.hooks(givenAccountHooksConfiguration(explorationRate))
.build();
}

private AccountHooksConfiguration givenAccountHooksConfiguration(Double explorationRate) {
final ObjectNode greenbidsNode = TestBidRequestProvider.MAPPER.createObjectNode();
greenbidsNode.put("enabled", true);
greenbidsNode.put("pbuid", "test-pbuid");
greenbidsNode.put("targetTpr", 0.60);
greenbidsNode.put("explorationRate", explorationRate);
final Map<String, ObjectNode> modules = Map.of("greenbids", greenbidsNode);
return AccountHooksConfiguration.of(null, modules, null);
}

private OnnxModelRunner givenOnnxModelRunner() throws OrtException, IOException {
final byte[] onnxModelBytes = Files.readAllBytes(Paths.get(
"src/test/resources/models_pbuid=test-pbuid.onnx"));
Expand All @@ -396,7 +429,6 @@ private ThrottlingThresholds givenThrottlingThresholds() throws IOException {

private BidRequest expectedUpdatedBidRequest(
UnaryOperator<BidRequest.BidRequestBuilder> bidRequestCustomizer,
Double explorationRate,
Device device) {

final Banner banner = givenBanner();
Expand All @@ -415,12 +447,13 @@ private BidRequest expectedUpdatedBidRequest(
.banner(banner)
.build();

return bidRequestCustomizer.apply(BidRequest.builder()
final BidRequest.BidRequestBuilder bidRequestBuilder = BidRequest.builder()
.id("request")
.imp(List.of(imp))
.site(givenSite(site -> site))
.device(device)
.ext(givenExtRequest(explorationRate))).build();
.device(device);

return bidRequestCustomizer.apply(bidRequestBuilder).build();
}

private AnalyticsResult expectedAnalyticsResult(Boolean isExploration, Boolean isKeptInAuction) {
Expand Down
Loading
Loading