From dea7e2e48af97797da05e9bbaaf4f7d4ef8c9da0 Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Thu, 5 Dec 2024 08:21:34 -0800 Subject: [PATCH 01/13] Greenbids RTD Accoung level config --- .../GreenbidsRealTimeDataConfiguration.java | 12 +++++-- .../GreenbidsRealTimeDataProperties.java | 6 ++++ ...alTimeDataProcessedAuctionRequestHook.java | 35 +++---------------- ...meDataProcessedAuctionRequestHookTest.java | 5 ++- 4 files changed, 24 insertions(+), 34 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataConfiguration.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataConfiguration.java index a6b47f7d6ad..f87ab62d6fa 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataConfiguration.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataConfiguration.java @@ -6,6 +6,7 @@ import com.google.cloud.storage.StorageOptions; import io.vertx.core.Vertx; import org.prebid.server.geolocation.CountryCodeMapper; +import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.Partner; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.filter.ThrottlingThresholds; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.ThrottlingThresholdsFactory; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.GreenbidsInferenceDataService; @@ -49,7 +50,8 @@ GreenbidsRealTimeDataModule greenbidsRealTimeDataModule( FilterService filterService, OnnxModelRunnerWithThresholds onnxModelRunnerWithThresholds, GreenbidsInferenceDataService greenbidsInferenceDataService, - GreenbidsInvocationService greenbidsInvocationService) { + GreenbidsInvocationService greenbidsInvocationService, + Partner partner) { return new GreenbidsRealTimeDataModule(List.of( new GreenbidsRealTimeDataProcessedAuctionRequestHook( @@ -57,7 +59,8 @@ GreenbidsRealTimeDataModule greenbidsRealTimeDataModule( filterService, onnxModelRunnerWithThresholds, greenbidsInferenceDataService, - greenbidsInvocationService))); + greenbidsInvocationService, + partner))); } @Bean @@ -71,6 +74,11 @@ Storage storage(GreenbidsRealTimeDataProperties properties) { .setProjectId(properties.getGoogleCloudGreenbidsProject()).build().getService(); } + @Bean + Partner partner(GreenbidsRealTimeDataProperties properties) { + return Partner.of(properties.getPbuid(), properties.getTargetTpr(), properties.getExplorationRate()); + } + @Bean OnnxModelRunnerFactory onnxModelRunnerFactory() { return new OnnxModelRunnerFactory(); diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataProperties.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataProperties.java index 4752a2e8840..1a55f787c9f 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataProperties.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataProperties.java @@ -24,4 +24,10 @@ public class GreenbidsRealTimeDataProperties { Long timeoutMs; Integer maxRedirects; + + String pbuid; + + Double targetTpr; + + Double explorationRate; } diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index 3b677a78a18..f6d56dae376 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -47,25 +47,27 @@ 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; private final OnnxModelRunnerWithThresholds onnxModelRunnerWithThresholds; private final GreenbidsInferenceDataService greenbidsInferenceDataService; private final GreenbidsInvocationService greenbidsInvocationService; + private final Partner partner; public GreenbidsRealTimeDataProcessedAuctionRequestHook( ObjectMapper mapper, FilterService filterService, OnnxModelRunnerWithThresholds onnxModelRunnerWithThresholds, GreenbidsInferenceDataService greenbidsInferenceDataService, - GreenbidsInvocationService greenbidsInvocationService) { + GreenbidsInvocationService greenbidsInvocationService, + Partner partner) { this.mapper = Objects.requireNonNull(mapper); this.filterService = Objects.requireNonNull(filterService); this.onnxModelRunnerWithThresholds = Objects.requireNonNull(onnxModelRunnerWithThresholds); this.greenbidsInferenceDataService = Objects.requireNonNull(greenbidsInferenceDataService); this.greenbidsInvocationService = Objects.requireNonNull(greenbidsInvocationService); + this.partner = Objects.requireNonNull(partner); } @Override @@ -75,12 +77,6 @@ public Future> call( final AuctionContext auctionContext = invocationContext.auctionContext(); final BidRequest bidRequest = auctionContext.getBidRequest(); - final Partner partner = parseBidRequestExt(bidRequest); - - if (partner == null) { - return Future.succeededFuture(toInvocationResult( - bidRequest, null, InvocationAction.no_action)); - } return Future.all( onnxModelRunnerWithThresholds.retrieveOnnxModelRunner(partner), @@ -94,29 +90,6 @@ public Future> call( 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) - .orElse(null); - } - - private boolean isNotEmptyObjectNode(JsonNode analytics) { - return analytics != null && analytics.isObject() && !analytics.isEmpty(); - } - - private Partner toPartner(ObjectNode adapterNode) { - try { - return mapper.treeToValue(adapterNode, Partner.class); - } catch (JsonProcessingException e) { - return null; - } - } - private Future> toInvocationResult( BidRequest bidRequest, Partner partner, diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java index 284741a1b68..568986af117 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java @@ -41,6 +41,7 @@ import org.prebid.server.hooks.modules.greenbids.real.time.data.core.OnnxModelRunnerWithThresholds; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.ThresholdCache; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.ThrottlingThresholdsFactory; +import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.Partner; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.filter.ThrottlingThresholds; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.result.AnalyticsResult; import org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider; @@ -140,12 +141,14 @@ public void setUp() throws IOException, GeoIp2Exception { TestBidRequestProvider.MAPPER, countryCodeMapper); final GreenbidsInvocationService greenbidsInvocationService = new GreenbidsInvocationService(); + final Partner partner = Partner.of("test-pbuid", 0.60, 0.0001); target = new GreenbidsRealTimeDataProcessedAuctionRequestHook( TestBidRequestProvider.MAPPER, filterService, onnxModelRunnerWithThresholds, greenbidsInferenceDataService, - greenbidsInvocationService); + greenbidsInvocationService, + partner); } @Test From 430e3c3e79bf6cd0d0a6a6bbcee639515d340618 Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Fri, 6 Dec 2024 02:28:25 -0800 Subject: [PATCH 02/13] keep account level config + bid request ext config --- ...alTimeDataProcessedAuctionRequestHook.java | 32 ++++++++++- ...meDataProcessedAuctionRequestHookTest.java | 56 ++++++++++++++++--- 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index f6d56dae376..62b49247001 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -47,6 +47,7 @@ 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; @@ -77,19 +78,44 @@ public Future> call( final AuctionContext auctionContext = invocationContext.auctionContext(); final BidRequest bidRequest = auctionContext.getBidRequest(); + final Partner appliedPartner = Optional.ofNullable(parseBidRequestExt(bidRequest)) + .orElse(partner); 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) + .orElse(null); + } + + private boolean isNotEmptyObjectNode(JsonNode analytics) { + return analytics != null && analytics.isObject() && !analytics.isEmpty(); + } + + private Partner toPartner(ObjectNode adapterNode) { + try { + return mapper.treeToValue(adapterNode, Partner.class); + } catch (JsonProcessingException e) { + return null; + } + } + private Future> toInvocationResult( BidRequest bidRequest, Partner partner, diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java index 568986af117..54177460d4b 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java @@ -152,7 +152,8 @@ public void setUp() throws IOException, GeoIp2Exception { } @Test - public void callShouldExitEarlyWhenPartnerNotActivatedInBidRequest() { + public void callShouldFilterBiddersAndFallbackToAccountLevelConfigWhenPartnerNotActivatedInBidRequest() + throws IOException, OrtException { // given final Banner banner = givenBanner(); @@ -162,24 +163,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 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, false); + final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false); // when final Future> future = target .call(null, invocationContext); final InvocationResult 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 @@ -259,7 +290,8 @@ public void callShouldFilterBiddersBasedOnModelWhenAnyFeatureNotAvailable() thro when(thresholdsCacheWithExpiration.getIfPresent("throttlingThresholds_test-pbuid")) .thenReturn(givenThrottlingThresholds()); - final BidRequest expectedBidRequest = expectedUpdatedBidRequest(request -> request, explorationRate, device); + final BidRequest expectedBidRequest = expectedUpdatedBidRequest( + request -> request, explorationRate, device, true); final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false); // when @@ -320,7 +352,7 @@ public void callShouldFilterBiddersBasedOnModelResults() throws OrtException, IO .thenReturn(givenThrottlingThresholds()); final BidRequest expectedBidRequest = expectedUpdatedBidRequest( - request -> request, explorationRate, device); + request -> request, explorationRate, device, true); final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false); // when @@ -407,7 +439,8 @@ private ThrottlingThresholds givenThrottlingThresholds() throws IOException { private BidRequest expectedUpdatedBidRequest( UnaryOperator bidRequestCustomizer, Double explorationRate, - Device device) { + Device device, + Boolean addExtRequest) { final Banner banner = givenBanner(); @@ -425,12 +458,17 @@ 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); + + if (addExtRequest) { + bidRequestBuilder.ext(givenExtRequest(explorationRate)); + } + + return bidRequestCustomizer.apply(bidRequestBuilder).build(); } private AnalyticsResult expectedAnalyticsResult(Boolean isExploration, Boolean isKeptInAuction) { From 8d28379ba5c4827067c3ef9e9fd095477c6bb2cb Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Tue, 10 Dec 2024 02:35:25 -0800 Subject: [PATCH 03/13] default account config json debug + TU --- .../GreenbidsRealTimeDataConfiguration.java | 12 +- .../GreenbidsRealTimeDataProperties.java | 6 - ...alTimeDataProcessedAuctionRequestHook.java | 25 +++- ...meDataProcessedAuctionRequestHookTest.java | 26 +++- .../greenbids/GreenbidsAnalyticsReporter.java | 22 +++- .../GreenbidsAnalyticsReporterTest.java | 120 +++++++++++++++--- 6 files changed, 164 insertions(+), 47 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataConfiguration.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataConfiguration.java index f87ab62d6fa..a6b47f7d6ad 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataConfiguration.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataConfiguration.java @@ -6,7 +6,6 @@ import com.google.cloud.storage.StorageOptions; import io.vertx.core.Vertx; import org.prebid.server.geolocation.CountryCodeMapper; -import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.Partner; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.filter.ThrottlingThresholds; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.ThrottlingThresholdsFactory; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.GreenbidsInferenceDataService; @@ -50,8 +49,7 @@ GreenbidsRealTimeDataModule greenbidsRealTimeDataModule( FilterService filterService, OnnxModelRunnerWithThresholds onnxModelRunnerWithThresholds, GreenbidsInferenceDataService greenbidsInferenceDataService, - GreenbidsInvocationService greenbidsInvocationService, - Partner partner) { + GreenbidsInvocationService greenbidsInvocationService) { return new GreenbidsRealTimeDataModule(List.of( new GreenbidsRealTimeDataProcessedAuctionRequestHook( @@ -59,8 +57,7 @@ GreenbidsRealTimeDataModule greenbidsRealTimeDataModule( filterService, onnxModelRunnerWithThresholds, greenbidsInferenceDataService, - greenbidsInvocationService, - partner))); + greenbidsInvocationService))); } @Bean @@ -74,11 +71,6 @@ Storage storage(GreenbidsRealTimeDataProperties properties) { .setProjectId(properties.getGoogleCloudGreenbidsProject()).build().getService(); } - @Bean - Partner partner(GreenbidsRealTimeDataProperties properties) { - return Partner.of(properties.getPbuid(), properties.getTargetTpr(), properties.getExplorationRate()); - } - @Bean OnnxModelRunnerFactory onnxModelRunnerFactory() { return new OnnxModelRunnerFactory(); diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataProperties.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataProperties.java index 1a55f787c9f..4752a2e8840 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataProperties.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/GreenbidsRealTimeDataProperties.java @@ -24,10 +24,4 @@ public class GreenbidsRealTimeDataProperties { Long timeoutMs; Integer maxRedirects; - - String pbuid; - - Double targetTpr; - - Double explorationRate; } diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index 62b49247001..96e47d23a94 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -35,6 +35,8 @@ 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; @@ -54,21 +56,18 @@ public class GreenbidsRealTimeDataProcessedAuctionRequestHook implements Process private final OnnxModelRunnerWithThresholds onnxModelRunnerWithThresholds; private final GreenbidsInferenceDataService greenbidsInferenceDataService; private final GreenbidsInvocationService greenbidsInvocationService; - private final Partner partner; public GreenbidsRealTimeDataProcessedAuctionRequestHook( ObjectMapper mapper, FilterService filterService, OnnxModelRunnerWithThresholds onnxModelRunnerWithThresholds, GreenbidsInferenceDataService greenbidsInferenceDataService, - GreenbidsInvocationService greenbidsInvocationService, - Partner partner) { + GreenbidsInvocationService greenbidsInvocationService) { this.mapper = Objects.requireNonNull(mapper); this.filterService = Objects.requireNonNull(filterService); this.onnxModelRunnerWithThresholds = Objects.requireNonNull(onnxModelRunnerWithThresholds); this.greenbidsInferenceDataService = Objects.requireNonNull(greenbidsInferenceDataService); this.greenbidsInvocationService = Objects.requireNonNull(greenbidsInvocationService); - this.partner = Objects.requireNonNull(partner); } @Override @@ -79,7 +78,7 @@ public Future> call( final AuctionContext auctionContext = invocationContext.auctionContext(); final BidRequest bidRequest = auctionContext.getBidRequest(); final Partner appliedPartner = Optional.ofNullable(parseBidRequestExt(bidRequest)) - .orElse(partner); + .orElse(parseAccountConfig(auctionContext)); return Future.all( onnxModelRunnerWithThresholds.retrieveOnnxModelRunner(appliedPartner), @@ -104,6 +103,22 @@ private Partner parseBidRequestExt(BidRequest bidRequest) { .orElse(null); } + private Partner parseAccountConfig(AuctionContext auctionContext) { + final Map modules = Optional.ofNullable(auctionContext) + .map(AuctionContext::getAccount) + .map(Account::getHooks) + .map(AccountHooksConfiguration::getModules) + .orElse(null); + + Partner partner = null; + if (modules != null && modules.containsKey("greenbids")) { + final ObjectNode moduleConfig = modules.get("greenbids"); + partner = toPartner(moduleConfig); + } + + return partner; + } + private boolean isNotEmptyObjectNode(JsonNode analytics) { return analytics != null && analytics.isObject() && !analytics.isEmpty(); } diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java index 54177460d4b..ff8dfe51ba0 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java @@ -41,7 +41,6 @@ import org.prebid.server.hooks.modules.greenbids.real.time.data.core.OnnxModelRunnerWithThresholds; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.ThresholdCache; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.ThrottlingThresholdsFactory; -import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.Partner; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.filter.ThrottlingThresholds; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.result.AnalyticsResult; import org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider; @@ -55,6 +54,8 @@ 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.IOException; import java.net.InetAddress; @@ -141,14 +142,12 @@ public void setUp() throws IOException, GeoIp2Exception { TestBidRequestProvider.MAPPER, countryCodeMapper); final GreenbidsInvocationService greenbidsInvocationService = new GreenbidsInvocationService(); - final Partner partner = Partner.of("test-pbuid", 0.60, 0.0001); target = new GreenbidsRealTimeDataProcessedAuctionRequestHook( TestBidRequestProvider.MAPPER, filterService, onnxModelRunnerWithThresholds, greenbidsInferenceDataService, - greenbidsInvocationService, - partner); + greenbidsInvocationService); } @Test @@ -411,7 +410,8 @@ private AuctionContext givenAuctionContext( final AuctionContext.AuctionContextBuilder auctionContextBuilder = AuctionContext.builder() .httpRequest(HttpRequestContext.builder().build()) - .bidRequest(bidRequest); + .bidRequest(bidRequest) + .account(givenAccount()); return auctionContextCustomizer.apply(auctionContextBuilder).build(); } @@ -422,6 +422,22 @@ private AuctionInvocationContext givenAuctionInvocationContext(AuctionContext au return invocationContext; } + private Account givenAccount() { + return Account.builder() + .id("test-account") + .hooks(givenAccountHooksConfiguration()) + .build(); + } + + private AccountHooksConfiguration givenAccountHooksConfiguration() { + final ObjectNode greenbidsNode = TestBidRequestProvider.MAPPER.createObjectNode(); + greenbidsNode.put("pbuid", "test-pbuid"); + greenbidsNode.put("targetTpr", 0.60); + greenbidsNode.put("explorationRate", 0.0001); + final Map 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")); diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java index daf51c9d74f..5bb67c382c7 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java @@ -54,6 +54,8 @@ import org.prebid.server.proto.openrtb.ext.request.ExtStoredRequest; import org.prebid.server.proto.openrtb.ext.response.seatnonbid.NonBid; import org.prebid.server.proto.openrtb.ext.response.seatnonbid.SeatNonBid; +import org.prebid.server.settings.model.Account; +import org.prebid.server.settings.model.AccountAnalyticsConfig; import org.prebid.server.util.HttpUtil; import org.prebid.server.version.PrebidVersionProvider; import org.prebid.server.vertx.httpclient.HttpClient; @@ -118,7 +120,9 @@ public Future processEvent(T event) { return Future.failedFuture(new PreBidException("Bid response or auction context cannot be null")); } - final GreenbidsPrebidExt greenbidsBidRequestExt = parseBidRequestExt(auctionContext.getBidRequest()); + final GreenbidsPrebidExt greenbidsBidRequestExt = Optional.ofNullable( + parseBidRequestExt(auctionContext.getBidRequest())) + .orElse(parseAccountConfig(auctionContext)); if (greenbidsBidRequestExt == null) { return Future.succeededFuture(); @@ -181,6 +185,22 @@ private GreenbidsPrebidExt parseBidRequestExt(BidRequest bidRequest) { .orElse(null); } + private GreenbidsPrebidExt parseAccountConfig(AuctionContext auctionContext) { + final Map modules = Optional.ofNullable(auctionContext) + .map(AuctionContext::getAccount) + .map(Account::getAnalytics) + .map(AccountAnalyticsConfig::getModules) + .orElse(null); + + GreenbidsPrebidExt greenbidsPrebidExt = null; + if (modules != null && modules.containsKey("greenbids")) { + final ObjectNode moduleConfig = modules.get("greenbids"); + greenbidsPrebidExt = toGreenbidsPrebidExt(moduleConfig); + } + + return greenbidsPrebidExt; + } + private boolean isNotEmptyObjectNode(JsonNode analytics) { return analytics != null && analytics.isObject() && !analytics.isEmpty(); } diff --git a/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java b/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java index 3e5e8678c2c..ebb6bceb546 100644 --- a/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java +++ b/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java @@ -1,5 +1,6 @@ package org.prebid.server.analytics.reporter.greenbids; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -65,6 +66,8 @@ import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceInvocationResult; import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceStage; import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceStageOutcome; +import org.prebid.server.settings.model.Account; +import org.prebid.server.settings.model.AccountAnalyticsConfig; import org.prebid.server.util.HttpUtil; import org.prebid.server.version.PrebidVersionProvider; import org.prebid.server.vertx.httpclient.HttpClient; @@ -155,7 +158,7 @@ public void shouldReceiveValidResponseOnAuctionContextWithAnalyticsTagForBanner( .build(); final AuctionContext auctionContext = givenAuctionContextWithAnalyticsTag( - context -> context, List.of(imp), true, true); + context -> context, List.of(imp), true, true, true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -213,7 +216,7 @@ public void shouldReceiveValidResponseOnAuctionContextForBanner() throws IOExcep .banner(banner) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -260,7 +263,7 @@ public void shouldReceiveValidResponseOnAuctionContextForVideo() throws IOExcept .video(video) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -306,7 +309,59 @@ public void shouldReceiveValidResponseWhenBannerFormatIsNull() throws IOExceptio .ext(impExtNode) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); + final AuctionEvent event = AuctionEvent.builder() + .auctionContext(auctionContext) + .bidResponse(auctionContext.getBidResponse()) + .build(); + + final HttpClientResponse mockResponse = mock(HttpClientResponse.class); + + when(mockResponse.getStatusCode()).thenReturn(202); + when(httpClient.post( + anyString(), + any(MultiMap.class), + anyString(), + anyLong())) + .thenReturn(Future.succeededFuture(mockResponse)); + final CommonMessage expectedCommonMessage = expectedCommonMessageBannerWithoutFormat(); + + // when + target.processEvent(event); + + // then + verify(httpClient).post( + eq(greenbidsAnalyticsProperties.getAnalyticsServerUrl()), + any(MultiMap.class), + jsonCaptor.capture(), + eq(greenbidsAnalyticsProperties.getTimeoutMs())); + + final String capturedJson = jsonCaptor.getValue(); + final CommonMessage capturedCommonMessage = jacksonMapper.mapper() + .readValue(capturedJson, CommonMessage.class); + assertThat(capturedCommonMessage).usingRecursiveComparison() + .ignoringFields("billingId", "greenbidsId") + .isEqualTo(expectedCommonMessage); + assertThat(capturedCommonMessage.getGreenbidsId()).isNotNull(); + assertThat(capturedCommonMessage.getBillingId()).isNotNull(); + } + + @Test + public void shouldReceiveValidResponseAndFallbackToAccountLevelConfigWhenPartnerNotActivatedInBidRequest() + throws JsonProcessingException { + // given + final Banner bannerWithoutFormat = givenBannerWithoutFormat(); + + final ObjectNode impExtNode = mapper.createObjectNode(); + impExtNode.set("prebid", givenPrebidBidderParamsNode()); + + final Imp imp = Imp.builder() + .id("adunitcodevalue") + .banner(bannerWithoutFormat) + .ext(impExtNode) + .build(); + + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, false); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -357,7 +412,7 @@ public void shouldReturnValidHeadersAndTimeouts() { .banner(banner) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -390,7 +445,7 @@ public void shouldReturnValidHeadersAndTimeouts() { @Test public void shouldFailWhenBidResponseIsNull() { // given - final AuctionContext auctionContext = givenAuctionContext(identity(), null, false); + final AuctionContext auctionContext = givenAuctionContext(identity(), null, false, true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -427,7 +482,7 @@ public void shouldFailOnEmptyImpExtension() { final Imp imp = Imp.builder() .banner(banner) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -454,7 +509,7 @@ public void shouldFailOnEncodeException() { .banner(banner) .ext(impExtNode) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -493,7 +548,7 @@ public void shouldFailOnUnexpectedResponseStatus() { .banner(banner) .ext(impExtNode) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -560,7 +615,7 @@ public void shouldFailOnDecodingImpExtPrebid() { .ext(prebidJsonNodes) .banner(givenBanner()) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -579,12 +634,14 @@ public void shouldFailOnDecodingImpExtPrebid() { private static AuctionContext givenAuctionContext( UnaryOperator auctionContextCustomizer, List imps, - boolean includeBidResponse) { + boolean includeBidResponse, + boolean addExtRequest) { final AuctionContext.AuctionContextBuilder auctionContextBuilder = AuctionContext.builder() .httpRequest(HttpRequestContext.builder().build()) - .bidRequest(givenBidRequest(request -> request, imps)) - .bidRejectionTrackers(Map.of("seat3", givenBidRejectionTracker())); + .bidRequest(givenBidRequest(request -> request, imps, addExtRequest)) + .bidRejectionTrackers(Map.of("seat3", givenBidRejectionTracker())) + .account(givenAccount()); if (includeBidResponse) { auctionContextBuilder.bidResponse(givenBidResponse(response -> response)); @@ -597,11 +654,13 @@ private static AuctionContext givenAuctionContextWithAnalyticsTag( UnaryOperator auctionContextCustomizer, List imps, boolean includeBidResponse, - boolean includeHookExecutionContextWithAnalyticsTag) { + boolean includeHookExecutionContextWithAnalyticsTag, + boolean addExtRequest) { final AuctionContext.AuctionContextBuilder auctionContextBuilder = AuctionContext.builder() .httpRequest(HttpRequestContext.builder().build()) - .bidRequest(givenBidRequest(request -> request, imps)) - .bidRejectionTrackers(Map.of("seat3", givenBidRejectionTracker())); + .bidRequest(givenBidRequest(request -> request, imps, addExtRequest)) + .bidRejectionTrackers(Map.of("seat3", givenBidRejectionTracker())) + .account(givenAccount()); if (includeHookExecutionContextWithAnalyticsTag) { final HookExecutionContext hookExecutionContext = givenHookExecutionContextWithAnalyticsTag(); @@ -615,15 +674,36 @@ private static AuctionContext givenAuctionContextWithAnalyticsTag( return auctionContextCustomizer.apply(auctionContextBuilder).build(); } + private static Account givenAccount() { + return Account.builder() + .id("test-account") + .analytics(givenAccountHooksConfiguration()) + .build(); + } + + private static AccountAnalyticsConfig givenAccountHooksConfiguration() { + final ObjectNode greenbidsNode = mapper.createObjectNode(); + greenbidsNode.put("pbuid", "leparisien"); + greenbidsNode.put("greenbidsSampling", 1.0); + final Map modules = Map.of("greenbids", greenbidsNode); + return AccountAnalyticsConfig.of(true, null, modules); + } + private static BidRequest givenBidRequest( UnaryOperator bidRequestCustomizer, - List imps) { - return bidRequestCustomizer.apply(BidRequest.builder() + List imps, + boolean addExtRequest) { + final BidRequest.BidRequestBuilder bidRequestBuilder = BidRequest.builder() .id("request1") .imp(imps) .site(givenSite(site -> site)) - .device(givenDevice(device -> device)) - .ext(givenExtRequest())).build(); + .device(givenDevice(device -> device)); + + if (addExtRequest) { + bidRequestBuilder.ext(givenExtRequest()); + } + + return bidRequestCustomizer.apply(bidRequestBuilder).build(); } private static Site givenSite(UnaryOperator siteCustomizer) { From 2006d5594a610bde0bbb01f38c89a9305f11581a Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Tue, 10 Dec 2024 03:19:09 -0800 Subject: [PATCH 04/13] empty commit From d95cba93576b69f0c9e817ee237d5113674e1e81 Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Wed, 11 Dec 2024 17:19:53 -0800 Subject: [PATCH 05/13] default account config + account config from auctioncontext --- .../real/time/data/model/data/Partner.java | 3 + ...alTimeDataProcessedAuctionRequestHook.java | 27 ++------ .../GreenbidsInferenceDataServiceTest.java | 6 +- .../core/GreenbidsInvocationServiceTest.java | 6 +- .../data/util/TestBidRequestProvider.java | 7 +-- ...meDataProcessedAuctionRequestHookTest.java | 62 ++++++++++--------- 6 files changed, 50 insertions(+), 61 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/Partner.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/Partner.java index 2be7c1887e8..90e9550b659 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/Partner.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/Partner.java @@ -11,6 +11,9 @@ @Value(staticConstructor = "of") public class Partner { + @JsonProperty(required = true) + Boolean enabled; + String pbuid; @JsonProperty("targetTpr") diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index 96e47d23a94..cfb4851527f 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -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; @@ -33,8 +32,6 @@ 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; @@ -49,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; @@ -77,8 +73,12 @@ public Future> call( final AuctionContext auctionContext = invocationContext.auctionContext(); final BidRequest bidRequest = auctionContext.getBidRequest(); - final Partner appliedPartner = Optional.ofNullable(parseBidRequestExt(bidRequest)) - .orElse(parseAccountConfig(auctionContext)); + final Partner appliedPartner = parseAccountConfig(auctionContext); + + if (!appliedPartner.getEnabled()) { + return Future.succeededFuture(toInvocationResult( + bidRequest, null, InvocationAction.no_action)); + } return Future.all( onnxModelRunnerWithThresholds.retrieveOnnxModelRunner(appliedPartner), @@ -92,17 +92,6 @@ public Future> call( 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) - .orElse(null); - } - private Partner parseAccountConfig(AuctionContext auctionContext) { final Map modules = Optional.ofNullable(auctionContext) .map(AuctionContext::getAccount) @@ -119,10 +108,6 @@ private Partner parseAccountConfig(AuctionContext auctionContext) { return partner; } - private boolean isNotEmptyObjectNode(JsonNode analytics) { - return analytics != null && analytics.isObject() && !analytics.isEmpty(); - } - private Partner toPartner(ObjectNode adapterNode) { try { return mapper.treeToValue(adapterNode, Partner.class); diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInferenceDataServiceTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInferenceDataServiceTest.java index fafc759ca11..e355c31d4c7 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInferenceDataServiceTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInferenceDataServiceTest.java @@ -74,7 +74,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); @@ -152,7 +152,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(); @@ -188,7 +188,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")); diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationServiceTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationServiceTest.java index 1bf0f5409e4..98b6f59955c 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationServiceTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationServiceTest.java @@ -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> impsBiddersFilterMap = givenImpsBiddersFilterMap(); final Partner partner = givenPartner(0.0); @@ -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> impsBiddersFilterMap = givenImpsBiddersFilterMap(); final Partner partner = givenPartner(1.0); @@ -121,6 +121,6 @@ private Map> givenImpsBiddersFilterMap() { } private Partner givenPartner(Double explorationRate) { - return Partner.of("test-pbuid", 0.60, explorationRate); + return Partner.of(true, "test-pbuid", 0.60, explorationRate); } } diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java index c66ba26d953..2d210b53977 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java @@ -11,7 +11,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; @@ -26,15 +25,13 @@ private TestBidRequestProvider() { } public static BidRequest givenBidRequest( UnaryOperator bidRequestCustomizer, List 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 siteCustomizer) { diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java index ff8dfe51ba0..e152a96e132 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java @@ -52,8 +52,6 @@ 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; @@ -164,8 +162,8 @@ public void callShouldFilterBiddersAndFallbackToAccountLevelConfigWhenPartnerNot 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")) @@ -174,7 +172,7 @@ public void callShouldFilterBiddersAndFallbackToAccountLevelConfigWhenPartnerNot .thenReturn(givenThrottlingThresholds()); final BidRequest expectedBidRequest = expectedUpdatedBidRequest( - request -> request, explorationRate, device, false); + request -> request, device); final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false); // when @@ -225,9 +223,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")) @@ -279,9 +276,8 @@ 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")) @@ -290,7 +286,7 @@ public void callShouldFilterBiddersBasedOnModelWhenAnyFeatureNotAvailable() thro .thenReturn(givenThrottlingThresholds()); final BidRequest expectedBidRequest = expectedUpdatedBidRequest( - request -> request, explorationRate, device, true); + request -> request, device); final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false); // when @@ -340,9 +336,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")) @@ -351,7 +346,7 @@ public void callShouldFilterBiddersBasedOnModelResults() throws OrtException, IO .thenReturn(givenThrottlingThresholds()); final BidRequest expectedBidRequest = expectedUpdatedBidRequest( - request -> request, explorationRate, device, true); + request -> request, device); final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false); // when @@ -389,6 +384,19 @@ public void callShouldFilterBiddersBasedOnModelResults() throws OrtException, IO .isEqualTo(expectedBidRequest); } + static DatabaseReader givenDatabaseReader() throws IOException { + final URL url = new URL("https://git.io/GeoLite2-Country.mmdb"); + final Path databasePath = Files.createTempFile("GeoLite2-Country", ".mmdb"); + + try ( + InputStream inputStream = url.openStream(); + FileOutputStream outputStream = new FileOutputStream(databasePath.toFile())) { + inputStream.transferTo(outputStream); + } + + return new DatabaseReader.Builder(databasePath.toFile()).build(); + } + static ExtRequest givenExtRequest(Double explorationRate) { final ObjectNode greenbidsNode = TestBidRequestProvider.MAPPER.createObjectNode(); greenbidsNode.put("pbuid", "test-pbuid"); @@ -406,12 +414,13 @@ static ExtRequest givenExtRequest(Double explorationRate) { private AuctionContext givenAuctionContext( BidRequest bidRequest, - UnaryOperator auctionContextCustomizer) { + UnaryOperator auctionContextCustomizer, + Double explorationRate) { final AuctionContext.AuctionContextBuilder auctionContextBuilder = AuctionContext.builder() .httpRequest(HttpRequestContext.builder().build()) .bidRequest(bidRequest) - .account(givenAccount()); + .account(givenAccount(explorationRate)); return auctionContextCustomizer.apply(auctionContextBuilder).build(); } @@ -422,18 +431,19 @@ private AuctionInvocationContext givenAuctionInvocationContext(AuctionContext au return invocationContext; } - private Account givenAccount() { + private Account givenAccount(Double explorationRate) { return Account.builder() .id("test-account") - .hooks(givenAccountHooksConfiguration()) + .hooks(givenAccountHooksConfiguration(explorationRate)) .build(); } - private AccountHooksConfiguration givenAccountHooksConfiguration() { + 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", 0.0001); + greenbidsNode.put("explorationRate", explorationRate); final Map modules = Map.of("greenbids", greenbidsNode); return AccountHooksConfiguration.of(null, modules, null); } @@ -454,9 +464,7 @@ private ThrottlingThresholds givenThrottlingThresholds() throws IOException { private BidRequest expectedUpdatedBidRequest( UnaryOperator bidRequestCustomizer, - Double explorationRate, - Device device, - Boolean addExtRequest) { + Device device) { final Banner banner = givenBanner(); @@ -480,10 +488,6 @@ private BidRequest expectedUpdatedBidRequest( .site(givenSite(site -> site)) .device(device); - if (addExtRequest) { - bidRequestBuilder.ext(givenExtRequest(explorationRate)); - } - return bidRequestCustomizer.apply(bidRequestBuilder).build(); } From 3bd151ef398aca17528653dfeb7345b823855939 Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Fri, 13 Dec 2024 07:28:56 -0800 Subject: [PATCH 06/13] analytics report remove bid req config --- .../greenbids/GreenbidsAnalyticsReporter.java | 28 +++++++++---------- .../greenbids/model/GreenbidsPrebidExt.java | 2 ++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java index 5bb67c382c7..6c98d80f876 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java @@ -76,7 +76,6 @@ public class GreenbidsAnalyticsReporter implements AnalyticsReporter { - private static final String BID_REQUEST_ANALYTICS_EXTENSION_NAME = "greenbids"; private static final int RANGE_16_BIT_INTEGER_DIVISION_BASIS = 0x10000; private static final String ANALYTICS_REQUEST_ORIGIN_HEADER = "X-Request-Origin"; private static final String PREBID_SERVER_HEADER_VALUE = "Prebid Server"; @@ -120,9 +119,7 @@ public Future processEvent(T event) { return Future.failedFuture(new PreBidException("Bid response or auction context cannot be null")); } - final GreenbidsPrebidExt greenbidsBidRequestExt = Optional.ofNullable( - parseBidRequestExt(auctionContext.getBidRequest())) - .orElse(parseAccountConfig(auctionContext)); + final GreenbidsPrebidExt greenbidsBidRequestExt = parseAccountConfig(auctionContext); if (greenbidsBidRequestExt == null) { return Future.succeededFuture(); @@ -165,6 +162,12 @@ public Future processEvent(T event) { .map(Device::getUa) .ifPresent(userAgent -> headers.add(HttpUtil.USER_AGENT_HEADER, userAgent)); + System.out.println( + "GreenbidsAnalyticsReporter/ processEvent \n" + + " commonMessageJson: " + commonMessageJson + "\n" + + " headers: " + headers + ); + final Future responseFuture = httpClient.post( greenbidsAnalyticsProperties.getAnalyticsServerUrl(), headers, @@ -174,17 +177,6 @@ public Future processEvent(T event) { return responseFuture.compose(this::processAnalyticServerResponse); } - private GreenbidsPrebidExt 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::toGreenbidsPrebidExt) - .orElse(null); - } - private GreenbidsPrebidExt parseAccountConfig(AuctionContext auctionContext) { final Map modules = Optional.ofNullable(auctionContext) .map(AuctionContext::getAccount) @@ -196,6 +188,12 @@ private GreenbidsPrebidExt parseAccountConfig(AuctionContext auctionContext) { if (modules != null && modules.containsKey("greenbids")) { final ObjectNode moduleConfig = modules.get("greenbids"); greenbidsPrebidExt = toGreenbidsPrebidExt(moduleConfig); + + System.out.println( + "GreenbidsAnalyticsReporter/ parseAccountConfig \n" + + " moduleConfig: " + moduleConfig + "\n" + + " greenbidsPrebidExt: " + greenbidsPrebidExt + ); } return greenbidsPrebidExt; diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsPrebidExt.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsPrebidExt.java index d5983205898..e0ec7e301fa 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsPrebidExt.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsPrebidExt.java @@ -6,6 +6,8 @@ @Value(staticConstructor = "of") public class GreenbidsPrebidExt { + Boolean enabled; + String pbuid; @JsonProperty("greenbidsSampling") From b305458f85909450a5f7cb44db0fb0f4a30b463e Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Mon, 6 Jan 2025 11:45:13 +0100 Subject: [PATCH 07/13] extrequest -> accountconfig: analytics and rtd + TU --- ...alTimeDataProcessedAuctionRequestHook.java | 23 +- .../data/util/TestBidRequestProvider.java | 30 +++ ...meDataProcessedAuctionRequestHookTest.java | 26 ++- .../greenbids/GreenbidsAnalyticsReporter.java | 46 ++-- .../GreenbidsAnalyticsReporterTest.java | 221 +++++++----------- 5 files changed, 176 insertions(+), 170 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index cfb4851527f..4ce2e8d710d 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -1,6 +1,7 @@ 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; @@ -32,6 +33,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; @@ -43,6 +46,7 @@ public class GreenbidsRealTimeDataProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { + private static final String BID_REQUEST_ANALYTICS_EXTENSION_NAME = "greenbids-rtd"; 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"; @@ -73,7 +77,8 @@ public Future> call( final AuctionContext auctionContext = invocationContext.auctionContext(); final BidRequest bidRequest = auctionContext.getBidRequest(); - final Partner appliedPartner = parseAccountConfig(auctionContext); + final Partner appliedPartner = Optional.ofNullable(parseBidRequestExt(auctionContext)) + .orElse(parseAccountConfig(auctionContext)); if (!appliedPartner.getEnabled()) { return Future.succeededFuture(toInvocationResult( @@ -92,6 +97,22 @@ public Future> call( bidRequest, null, InvocationAction.no_action))); } + private Partner parseBidRequestExt(AuctionContext auctionContext) { + return Optional.ofNullable(auctionContext) + .map(AuctionContext::getBidRequest) + .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) + .orElse(null); + } + + private boolean isNotEmptyObjectNode(JsonNode analytics) { + return analytics != null && analytics.isObject() && !analytics.isEmpty(); + } + private Partner parseAccountConfig(AuctionContext auctionContext) { final Map modules = Optional.ofNullable(auctionContext) .map(AuctionContext::getAccount) diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java index 2d210b53977..7cb8e902dff 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java @@ -11,6 +11,8 @@ 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 org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; import java.util.Collections; import java.util.List; @@ -34,6 +36,34 @@ public static BidRequest givenBidRequest( .device(device)).build(); } + public static BidRequest givenBidRequestWithExtension( + UnaryOperator bidRequestCustomizer, + List imps) { + final BidRequest.BidRequestBuilder bidRequestBuilder = BidRequest.builder() + .id("request") + .imp(imps) + .site(givenSite(site -> site)) + .device(givenDevice(device -> device)) + .ext(givenExtRequest()); + + return bidRequestCustomizer.apply(bidRequestBuilder).build(); + } + + public static ExtRequest givenExtRequest() { + final ObjectNode greenbidsNode = new ObjectMapper().createObjectNode(); + greenbidsNode.put("pbuid", "leparisien"); + greenbidsNode.put("greenbidsSampling", 1.0); + + final ObjectNode analyticsNode = new ObjectMapper().createObjectNode(); + analyticsNode.set("greenbids", greenbidsNode); + + return ExtRequest.of( + ExtRequestPrebid + .builder() + .analytics(analyticsNode) + .build()); + } + public static Site givenSite(UnaryOperator siteCustomizer) { return siteCustomizer.apply(Site.builder().domain("www.leparisien.fr")).build(); } diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java index e152a96e132..ece5a6b1407 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java @@ -72,8 +72,10 @@ import static org.mockito.Mockito.when; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenBanner; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenBidRequest; +import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenBidRequestWithExtension; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenDevice; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenDeviceWithoutUserAgent; +import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenExtRequest; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenImpExt; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenSite; @@ -149,7 +151,7 @@ public void setUp() throws IOException, GeoIp2Exception { } @Test - public void callShouldFilterBiddersAndFallbackToAccountLevelConfigWhenPartnerNotActivatedInBidRequest() + public void callShouldFilterBiddersWhenPartnerActivatedInBidRequest() throws IOException, OrtException { // given final Banner banner = givenBanner(); @@ -162,8 +164,11 @@ public void callShouldFilterBiddersAndFallbackToAccountLevelConfigWhenPartnerNot final Double explorationRate = 0.0001; final Device device = givenDevice(identity()); - final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device); - final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context, explorationRate); + final BidRequest bidRequest = givenBidRequestWithExtension(identity(), List.of(imp)); + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + context -> context, + explorationRate); final AuctionInvocationContext invocationContext = givenAuctionInvocationContext(auctionContext); when(invocationContext.auctionContext()).thenReturn(auctionContext); when(modelCacheWithExpiration.getIfPresent("onnxModelRunner_test-pbuid")) @@ -172,7 +177,7 @@ public void callShouldFilterBiddersAndFallbackToAccountLevelConfigWhenPartnerNot .thenReturn(givenThrottlingThresholds()); final BidRequest expectedBidRequest = expectedUpdatedBidRequest( - request -> request, device); + request -> request, device, true); final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false); // when @@ -204,7 +209,7 @@ public void callShouldFilterBiddersAndFallbackToAccountLevelConfigWhenPartnerNot + ".values._children" + ".adunitcodevalue._children" + ".greenbids._children.fingerprint") - .isEqualTo(toAnalyticsTags(List.of(expectedAnalyticsResult))); // NOK + .isEqualTo(toAnalyticsTags(List.of(expectedAnalyticsResult))); assertThat(fingerprint).isNotNull(); assertThat(resultBidRequest).usingRecursiveComparison() .isEqualTo(expectedBidRequest); @@ -286,7 +291,7 @@ public void callShouldFilterBiddersBasedOnModelWhenAnyFeatureNotAvailable() thro .thenReturn(givenThrottlingThresholds()); final BidRequest expectedBidRequest = expectedUpdatedBidRequest( - request -> request, device); + request -> request, device, false); final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false); // when @@ -346,7 +351,7 @@ public void callShouldFilterBiddersBasedOnModelResults() throws OrtException, IO .thenReturn(givenThrottlingThresholds()); final BidRequest expectedBidRequest = expectedUpdatedBidRequest( - request -> request, device); + request -> request, device, false); final AnalyticsResult expectedAnalyticsResult = expectedAnalyticsResult(false, false); // when @@ -464,7 +469,8 @@ private ThrottlingThresholds givenThrottlingThresholds() throws IOException { private BidRequest expectedUpdatedBidRequest( UnaryOperator bidRequestCustomizer, - Device device) { + Device device, + Boolean isExtRequest) { final Banner banner = givenBanner(); @@ -488,6 +494,10 @@ private BidRequest expectedUpdatedBidRequest( .site(givenSite(site -> site)) .device(device); + if (isExtRequest) { + bidRequestBuilder.ext(givenExtRequest()); + } + return bidRequestCustomizer.apply(bidRequestBuilder).build(); } diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java index 6c98d80f876..0680a1a53d6 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java @@ -76,6 +76,7 @@ public class GreenbidsAnalyticsReporter implements AnalyticsReporter { + private static final String BID_REQUEST_ANALYTICS_EXTENSION_NAME = "greenbids"; private static final int RANGE_16_BIT_INTEGER_DIVISION_BASIS = 0x10000; private static final String ANALYTICS_REQUEST_ORIGIN_HEADER = "X-Request-Origin"; private static final String PREBID_SERVER_HEADER_VALUE = "Prebid Server"; @@ -119,9 +120,10 @@ public Future processEvent(T event) { return Future.failedFuture(new PreBidException("Bid response or auction context cannot be null")); } - final GreenbidsPrebidExt greenbidsBidRequestExt = parseAccountConfig(auctionContext); + final GreenbidsPrebidExt greenbidsPrebidExt = Optional.ofNullable(parseBidRequestExt(auctionContext)) + .orElse(parseAccountConfig(auctionContext)); - if (greenbidsBidRequestExt == null) { + if (greenbidsPrebidExt == null) { return Future.succeededFuture(); } @@ -132,7 +134,7 @@ public Future processEvent(T event) { final String greenbidsId = greenbidsId(analyticsResultFromAnalyticsTag); - if (!isSampled(greenbidsBidRequestExt.getGreenbidsSampling(), greenbidsId)) { + if (!isSampled(greenbidsPrebidExt.getGreenbidsSampling(), greenbidsId)) { return Future.succeededFuture(); } @@ -143,7 +145,7 @@ public Future processEvent(T event) { bidResponse, greenbidsId, billingId, - greenbidsBidRequestExt, + greenbidsPrebidExt, analyticsResultFromAnalyticsTag); commonMessageJson = jacksonMapper.encodeToString(commonMessage); } catch (PreBidException e) { @@ -162,12 +164,6 @@ public Future processEvent(T event) { .map(Device::getUa) .ifPresent(userAgent -> headers.add(HttpUtil.USER_AGENT_HEADER, userAgent)); - System.out.println( - "GreenbidsAnalyticsReporter/ processEvent \n" + - " commonMessageJson: " + commonMessageJson + "\n" + - " headers: " + headers - ); - final Future responseFuture = httpClient.post( greenbidsAnalyticsProperties.getAnalyticsServerUrl(), headers, @@ -177,6 +173,22 @@ public Future processEvent(T event) { return responseFuture.compose(this::processAnalyticServerResponse); } + private GreenbidsPrebidExt parseBidRequestExt(AuctionContext auctionContext) { + return Optional.ofNullable(auctionContext) + .map(AuctionContext::getBidRequest) + .map(BidRequest::getExt) + .map(ExtRequest::getPrebid) + .map(ExtRequestPrebid::getAnalytics) + .filter(this::isNotEmptyObjectNode) + .map(analytics -> (ObjectNode) analytics.get(BID_REQUEST_ANALYTICS_EXTENSION_NAME)) + .map(this::toGreenbidsPrebidExt) + .orElse(null); + } + + private boolean isNotEmptyObjectNode(JsonNode analytics) { + return analytics != null && analytics.isObject() && !analytics.isEmpty(); + } + private GreenbidsPrebidExt parseAccountConfig(AuctionContext auctionContext) { final Map modules = Optional.ofNullable(auctionContext) .map(AuctionContext::getAccount) @@ -185,24 +197,14 @@ private GreenbidsPrebidExt parseAccountConfig(AuctionContext auctionContext) { .orElse(null); GreenbidsPrebidExt greenbidsPrebidExt = null; - if (modules != null && modules.containsKey("greenbids")) { - final ObjectNode moduleConfig = modules.get("greenbids"); + if (modules != null && modules.containsKey(BID_REQUEST_ANALYTICS_EXTENSION_NAME)) { + final ObjectNode moduleConfig = modules.get(BID_REQUEST_ANALYTICS_EXTENSION_NAME); greenbidsPrebidExt = toGreenbidsPrebidExt(moduleConfig); - - System.out.println( - "GreenbidsAnalyticsReporter/ parseAccountConfig \n" + - " moduleConfig: " + moduleConfig + "\n" + - " greenbidsPrebidExt: " + greenbidsPrebidExt - ); } return greenbidsPrebidExt; } - private boolean isNotEmptyObjectNode(JsonNode analytics) { - return analytics != null && analytics.isObject() && !analytics.isEmpty(); - } - private GreenbidsPrebidExt toGreenbidsPrebidExt(ObjectNode adapterNode) { try { return jacksonMapper.mapper().treeToValue(adapterNode, GreenbidsPrebidExt.class); diff --git a/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java b/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java index ebb6bceb546..0093862d936 100644 --- a/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java +++ b/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java @@ -1,6 +1,5 @@ package org.prebid.server.analytics.reporter.greenbids; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -55,17 +54,6 @@ 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.proto.openrtb.ext.response.ExtBidResponse; -import org.prebid.server.proto.openrtb.ext.response.ExtBidResponsePrebid; -import org.prebid.server.proto.openrtb.ext.response.ExtModules; -import org.prebid.server.proto.openrtb.ext.response.ExtModulesTrace; -import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceAnalyticsActivity; -import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceAnalyticsResult; -import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceAnalyticsTags; -import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceGroup; -import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceInvocationResult; -import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceStage; -import org.prebid.server.proto.openrtb.ext.response.ExtModulesTraceStageOutcome; import org.prebid.server.settings.model.Account; import org.prebid.server.settings.model.AccountAnalyticsConfig; import org.prebid.server.util.HttpUtil; @@ -143,7 +131,8 @@ public void setUp() { } @Test - public void shouldReceiveValidResponseOnAuctionContextWithAnalyticsTagForBanner() throws IOException { + public void shouldReceiveValidResponseOnAuctionContextForBannerWhenPartnerActivatedInBidRequest() + throws IOException { // given final Banner banner = givenBanner(); @@ -157,8 +146,10 @@ public void shouldReceiveValidResponseOnAuctionContextWithAnalyticsTagForBanner( .banner(banner) .build(); - final AuctionContext auctionContext = givenAuctionContextWithAnalyticsTag( - context -> context, List.of(imp), true, true, true); + final AuctionContext auctionContext = givenAuctionContext( + builder -> builder.bidRequest(givenBidRequestWithExtension(identity(), List.of(imp))), + List.of(imp), + true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -168,16 +159,15 @@ public void shouldReceiveValidResponseOnAuctionContextWithAnalyticsTagForBanner( when(mockResponse.getStatusCode()).thenReturn(202); when(httpClient.post(anyString(), any(MultiMap.class), anyString(), anyLong())) .thenReturn(Future.succeededFuture(mockResponse)); - final CommonMessage expectedCommonMessage = givenCommonMessageForBannerWithRtb2Imp(); + final CommonMessage expectedCommonMessage = expectedCommonMessageForBanner(); // when - final Future result = target.processEvent(event); + target.processEvent(event); // then - assertThat(result.succeeded()).isTrue(); verify(httpClient).post( eq(greenbidsAnalyticsProperties.getAnalyticsServerUrl()), - headersCaptor.capture(), + any(MultiMap.class), jsonCaptor.capture(), eq(greenbidsAnalyticsProperties.getTimeoutMs())); @@ -190,19 +180,10 @@ public void shouldReceiveValidResponseOnAuctionContextWithAnalyticsTagForBanner( .isEqualTo(expectedCommonMessage); assertThat(capturedCommonMessage.getGreenbidsId()).isNotNull(); assertThat(capturedCommonMessage.getBillingId()).isNotNull(); - capturedCommonMessage.getAdUnits().forEach(adUnit -> { - assertThat(adUnit.getOrtb2ImpResult().getExt().getGreenbids().getFingerprint()).isNotNull(); - assertThat(adUnit.getOrtb2ImpResult().getExt().getTid()).isNotNull(); - }); - - assertThat(headersCaptor.getValue().get(HttpUtil.ACCEPT_HEADER)) - .isEqualTo(HttpHeaderValues.APPLICATION_JSON.toString()); - assertThat(headersCaptor.getValue().get(HttpUtil.CONTENT_TYPE_HEADER)) - .isEqualTo(HttpHeaderValues.APPLICATION_JSON.toString()); } @Test - public void shouldReceiveValidResponseOnAuctionContextForBanner() throws IOException { + public void shouldReceiveValidResponseOnAuctionContextWithAnalyticsTagForBanner() throws IOException { // given final Banner banner = givenBanner(); @@ -216,7 +197,8 @@ public void shouldReceiveValidResponseOnAuctionContextForBanner() throws IOExcep .banner(banner) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); + final AuctionContext auctionContext = givenAuctionContextWithAnalyticsTag( + context -> context, List.of(imp), true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -226,15 +208,16 @@ public void shouldReceiveValidResponseOnAuctionContextForBanner() throws IOExcep when(mockResponse.getStatusCode()).thenReturn(202); when(httpClient.post(anyString(), any(MultiMap.class), anyString(), anyLong())) .thenReturn(Future.succeededFuture(mockResponse)); - final CommonMessage expectedCommonMessage = expectedCommonMessageForBanner(); + final CommonMessage expectedCommonMessage = givenCommonMessageForBannerWithRtb2Imp(); // when - target.processEvent(event); + final Future result = target.processEvent(event); // then + assertThat(result.succeeded()).isTrue(); verify(httpClient).post( eq(greenbidsAnalyticsProperties.getAnalyticsServerUrl()), - any(MultiMap.class), + headersCaptor.capture(), jsonCaptor.capture(), eq(greenbidsAnalyticsProperties.getTimeoutMs())); @@ -247,23 +230,33 @@ public void shouldReceiveValidResponseOnAuctionContextForBanner() throws IOExcep .isEqualTo(expectedCommonMessage); assertThat(capturedCommonMessage.getGreenbidsId()).isNotNull(); assertThat(capturedCommonMessage.getBillingId()).isNotNull(); + capturedCommonMessage.getAdUnits().forEach(adUnit -> { + assertThat(adUnit.getOrtb2ImpResult().getExt().getGreenbids().getFingerprint()).isNotNull(); + assertThat(adUnit.getOrtb2ImpResult().getExt().getTid()).isNotNull(); + }); + + assertThat(headersCaptor.getValue().get(HttpUtil.ACCEPT_HEADER)) + .isEqualTo(HttpHeaderValues.APPLICATION_JSON.toString()); + assertThat(headersCaptor.getValue().get(HttpUtil.CONTENT_TYPE_HEADER)) + .isEqualTo(HttpHeaderValues.APPLICATION_JSON.toString()); } @Test - public void shouldReceiveValidResponseOnAuctionContextForVideo() throws IOException { + public void shouldReceiveValidResponseOnAuctionContextForBanner() throws IOException { // given - final Video video = givenVideo(); + final Banner banner = givenBanner(); final ObjectNode impExtNode = mapper.createObjectNode(); + impExtNode.set("gpid", TextNode.valueOf("gpidvalue")); impExtNode.set("prebid", givenPrebidBidderParamsNode()); final Imp imp = Imp.builder() .id("adunitcodevalue") .ext(impExtNode) - .video(video) + .banner(banner) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -273,7 +266,7 @@ public void shouldReceiveValidResponseOnAuctionContextForVideo() throws IOExcept when(mockResponse.getStatusCode()).thenReturn(202); when(httpClient.post(anyString(), any(MultiMap.class), anyString(), anyLong())) .thenReturn(Future.succeededFuture(mockResponse)); - final CommonMessage expectedCommonMessage = expectedCommonMessageForVideo(); + final CommonMessage expectedCommonMessage = expectedCommonMessageForBanner(); // when target.processEvent(event); @@ -288,6 +281,7 @@ public void shouldReceiveValidResponseOnAuctionContextForVideo() throws IOExcept final String capturedJson = jsonCaptor.getValue(); final CommonMessage capturedCommonMessage = jacksonMapper.mapper() .readValue(capturedJson, CommonMessage.class); + assertThat(capturedCommonMessage).usingRecursiveComparison() .ignoringFields("billingId", "greenbidsId") .isEqualTo(expectedCommonMessage); @@ -296,35 +290,30 @@ public void shouldReceiveValidResponseOnAuctionContextForVideo() throws IOExcept } @Test - public void shouldReceiveValidResponseWhenBannerFormatIsNull() throws IOException { + public void shouldReceiveValidResponseOnAuctionContextForVideo() throws IOException { // given - final Banner bannerWithoutFormat = givenBannerWithoutFormat(); + final Video video = givenVideo(); final ObjectNode impExtNode = mapper.createObjectNode(); impExtNode.set("prebid", givenPrebidBidderParamsNode()); final Imp imp = Imp.builder() .id("adunitcodevalue") - .banner(bannerWithoutFormat) .ext(impExtNode) + .video(video) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) .build(); final HttpClientResponse mockResponse = mock(HttpClientResponse.class); - when(mockResponse.getStatusCode()).thenReturn(202); - when(httpClient.post( - anyString(), - any(MultiMap.class), - anyString(), - anyLong())) + when(httpClient.post(anyString(), any(MultiMap.class), anyString(), anyLong())) .thenReturn(Future.succeededFuture(mockResponse)); - final CommonMessage expectedCommonMessage = expectedCommonMessageBannerWithoutFormat(); + final CommonMessage expectedCommonMessage = expectedCommonMessageForVideo(); // when target.processEvent(event); @@ -347,8 +336,7 @@ public void shouldReceiveValidResponseWhenBannerFormatIsNull() throws IOExceptio } @Test - public void shouldReceiveValidResponseAndFallbackToAccountLevelConfigWhenPartnerNotActivatedInBidRequest() - throws JsonProcessingException { + public void shouldReceiveValidResponseWhenBannerFormatIsNull() throws IOException { // given final Banner bannerWithoutFormat = givenBannerWithoutFormat(); @@ -361,7 +349,7 @@ public void shouldReceiveValidResponseAndFallbackToAccountLevelConfigWhenPartner .ext(impExtNode) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, false); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -412,7 +400,7 @@ public void shouldReturnValidHeadersAndTimeouts() { .banner(banner) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -445,7 +433,7 @@ public void shouldReturnValidHeadersAndTimeouts() { @Test public void shouldFailWhenBidResponseIsNull() { // given - final AuctionContext auctionContext = givenAuctionContext(identity(), null, false, true); + final AuctionContext auctionContext = givenAuctionContext(identity(), null, false); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -482,7 +470,7 @@ public void shouldFailOnEmptyImpExtension() { final Imp imp = Imp.builder() .banner(banner) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -509,7 +497,7 @@ public void shouldFailOnEncodeException() { .banner(banner) .ext(impExtNode) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -548,7 +536,7 @@ public void shouldFailOnUnexpectedResponseStatus() { .banner(banner) .ext(impExtNode) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -576,8 +564,9 @@ public void shouldFailWhenAdUnitsListIsEmpty() { when(auctionContext.getBidRequest()) .thenReturn(BidRequest.builder() .id("request1") - .ext(givenExtRequest()) + .imp(Collections.emptyList()) .build()); + when(auctionContext.getAccount()).thenReturn(givenAccount()); final AuctionEvent event = mock(AuctionEvent.class); when(event.getAuctionContext()).thenReturn(auctionContext); @@ -615,7 +604,7 @@ public void shouldFailOnDecodingImpExtPrebid() { .ext(prebidJsonNodes) .banner(givenBanner()) .build(); - final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true, true); + final AuctionContext auctionContext = givenAuctionContext(identity(), List.of(imp), true); final AuctionEvent event = AuctionEvent.builder() .auctionContext(auctionContext) .bidResponse(auctionContext.getBidResponse()) @@ -634,12 +623,11 @@ public void shouldFailOnDecodingImpExtPrebid() { private static AuctionContext givenAuctionContext( UnaryOperator auctionContextCustomizer, List imps, - boolean includeBidResponse, - boolean addExtRequest) { + boolean includeBidResponse) { final AuctionContext.AuctionContextBuilder auctionContextBuilder = AuctionContext.builder() .httpRequest(HttpRequestContext.builder().build()) - .bidRequest(givenBidRequest(request -> request, imps, addExtRequest)) + .bidRequest(givenBidRequest(request -> request, imps)) .bidRejectionTrackers(Map.of("seat3", givenBidRejectionTracker())) .account(givenAccount()); @@ -653,19 +641,15 @@ private static AuctionContext givenAuctionContext( private static AuctionContext givenAuctionContextWithAnalyticsTag( UnaryOperator auctionContextCustomizer, List imps, - boolean includeBidResponse, - boolean includeHookExecutionContextWithAnalyticsTag, - boolean addExtRequest) { + boolean includeBidResponse) { final AuctionContext.AuctionContextBuilder auctionContextBuilder = AuctionContext.builder() .httpRequest(HttpRequestContext.builder().build()) - .bidRequest(givenBidRequest(request -> request, imps, addExtRequest)) + .bidRequest(givenBidRequest(request -> request, imps)) .bidRejectionTrackers(Map.of("seat3", givenBidRejectionTracker())) .account(givenAccount()); - if (includeHookExecutionContextWithAnalyticsTag) { - final HookExecutionContext hookExecutionContext = givenHookExecutionContextWithAnalyticsTag(); - auctionContextBuilder.hookExecutionContext(hookExecutionContext); - } + final HookExecutionContext hookExecutionContext = givenHookExecutionContextWithAnalyticsTag(); + auctionContextBuilder.hookExecutionContext(hookExecutionContext); if (includeBidResponse) { auctionContextBuilder.bidResponse(givenBidResponse(response -> response)); @@ -691,21 +675,44 @@ private static AccountAnalyticsConfig givenAccountHooksConfiguration() { private static BidRequest givenBidRequest( UnaryOperator bidRequestCustomizer, - List imps, - boolean addExtRequest) { + List imps) { final BidRequest.BidRequestBuilder bidRequestBuilder = BidRequest.builder() .id("request1") .imp(imps) .site(givenSite(site -> site)) .device(givenDevice(device -> device)); - if (addExtRequest) { - bidRequestBuilder.ext(givenExtRequest()); - } + return bidRequestCustomizer.apply(bidRequestBuilder).build(); + } + + private static BidRequest givenBidRequestWithExtension( + UnaryOperator bidRequestCustomizer, + List imps) { + final BidRequest.BidRequestBuilder bidRequestBuilder = BidRequest.builder() + .id("request1") + .imp(imps) + .site(givenSite(site -> site)) + .device(givenDevice(device -> device)) + .ext(givenExtRequest()); return bidRequestCustomizer.apply(bidRequestBuilder).build(); } + private static ExtRequest givenExtRequest() { + final ObjectNode greenbidsNode = new ObjectMapper().createObjectNode(); + greenbidsNode.put("pbuid", "leparisien"); + greenbidsNode.put("greenbidsSampling", 1.0); + + final ObjectNode analyticsNode = new ObjectMapper().createObjectNode(); + analyticsNode.set("greenbids", greenbidsNode); + + return ExtRequest.of( + ExtRequestPrebid + .builder() + .analytics(analyticsNode) + .build()); + } + private static Site givenSite(UnaryOperator siteCustomizer) { return siteCustomizer.apply(Site.builder().domain("www.leparisien.fr")).build(); } @@ -765,55 +772,6 @@ private static BidResponse givenBidResponse(UnaryOperator bidResponseCustomizer) { - final ObjectNode analyticsResultNode = mapper.valueToTree( - singletonMap( - "adunitcodevalue", - createAnalyticsResultNode())); - - final ExtModulesTraceAnalyticsTags analyticsTags = ExtModulesTraceAnalyticsTags.of( - Collections.singletonList( - ExtModulesTraceAnalyticsActivity.of( - null, null, Collections.singletonList( - ExtModulesTraceAnalyticsResult.of( - null, analyticsResultNode, null))))); - - final ExtModulesTraceInvocationResult invocationResult = ExtModulesTraceInvocationResult.builder() - .hookId(HookId.of("greenbids-real-time-data", null)) - .analyticsTags(analyticsTags) - .build(); - - final ExtModulesTraceStageOutcome outcome = ExtModulesTraceStageOutcome.of( - "auction-request", null, - Collections.singletonList(ExtModulesTraceGroup.of( - null, Collections.singletonList(invocationResult)))); - - final ExtModulesTraceStage stage = ExtModulesTraceStage.of( - Stage.processed_auction_request, null, - Collections.singletonList(outcome)); - - final ExtModulesTrace modulesTrace = ExtModulesTrace.of(null, Collections.singletonList(stage)); - - final ExtModules modules = ExtModules.of(null, null, modulesTrace); - - final ExtBidResponsePrebid prebid = ExtBidResponsePrebid.builder().modules(modules).build(); - - final ExtBidResponse extBidResponse = ExtBidResponse.builder().prebid(prebid).build(); - - return bidResponseCustomizer.apply(BidResponse.builder() - .id("response2") - .seatbid(List.of( - givenSeatBid( - seatBid -> seatBid.seat("seat1"), - bid -> bid.id("bid1").price(BigDecimal.valueOf(1.5))), - givenSeatBid( - seatBid -> seatBid.seat("seat2"), - bid -> bid.id("bid2").price(BigDecimal.valueOf(0.5))))) - .cur("USD") - .ext(extBidResponse)).build(); - } - private static ObjectNode createAnalyticsResultNode() { final ObjectNode keptInAuctionNode = new ObjectNode(JsonNodeFactory.instance); keptInAuctionNode.put("seat1", true); @@ -883,21 +841,6 @@ private static ObjectNode givenPrebidBidderParamsNode() { return prebidNode; } - private static ExtRequest givenExtRequest() { - final ObjectNode greenbidsNode = new ObjectMapper().createObjectNode(); - greenbidsNode.put("pbuid", "leparisien"); - greenbidsNode.put("greenbidsSampling", 1.0); - - final ObjectNode analyticsNode = new ObjectMapper().createObjectNode(); - analyticsNode.set("greenbids", greenbidsNode); - - return ExtRequest.of( - ExtRequestPrebid - .builder() - .analytics(analyticsNode) - .build()); - } - private static CommonMessage expectedCommonMessageForBanner() { return expectedCommonMessage( adUnit -> adUnit From 6097fa0e6360d6ddd613696541ad92845548223f Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Mon, 6 Jan 2025 16:50:07 +0100 Subject: [PATCH 08/13] fix review --- .../data/core/GreenbidsInvocationService.java | 10 ++-- .../core/OnnxModelRunnerWithThresholds.java | 16 +++---- .../{Partner.java => GreenbidsConfig.java} | 5 +- ...alTimeDataProcessedAuctionRequestHook.java | 48 ++++++++----------- .../core/GreenbidsInvocationServiceTest.java | 14 +++--- .../greenbids/GreenbidsAnalyticsReporter.java | 37 ++++++-------- ...idsPrebidExt.java => GreenbidsConfig.java} | 4 +- 7 files changed, 57 insertions(+), 77 deletions(-) rename extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/{Partner.java => GreenbidsConfig.java} (93%) rename src/main/java/org/prebid/server/analytics/reporter/greenbids/model/{GreenbidsPrebidExt.java => GreenbidsConfig.java} (82%) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java index 67d42d47bc2..2b2e615d693 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java @@ -7,7 +7,7 @@ import org.apache.commons.lang3.StringUtils; import org.prebid.server.analytics.reporter.greenbids.model.ExplorationResult; import org.prebid.server.analytics.reporter.greenbids.model.Ortb2ImpExtResult; -import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.Partner; +import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.GreenbidsConfig; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.result.AnalyticsResult; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.result.GreenbidsInvocationResult; import org.prebid.server.hooks.v1.InvocationAction; @@ -23,12 +23,12 @@ public class GreenbidsInvocationService { private static final int RANGE_16_BIT_INTEGER_DIVISION_BASIS = 0x10000; public GreenbidsInvocationResult createGreenbidsInvocationResult( - Partner partner, + GreenbidsConfig greenbidsConfig, BidRequest bidRequest, Map> impsBiddersFilterMap) { final String greenbidsId = UUID.randomUUID().toString(); - final boolean isExploration = isExploration(partner, greenbidsId); + final boolean isExploration = isExploration(greenbidsConfig, greenbidsId); final BidRequest updatedBidRequest = isExploration ? bidRequest @@ -49,10 +49,10 @@ public GreenbidsInvocationResult createGreenbidsInvocationResult( return GreenbidsInvocationResult.of(updatedBidRequest, invocationAction, analyticsResult); } - private Boolean isExploration(Partner partner, String greenbidsId) { + private Boolean isExploration(GreenbidsConfig greenbidsConfig, String greenbidsId) { final int hashInt = Integer.parseInt( greenbidsId.substring(greenbidsId.length() - 4), 16); - return hashInt < partner.getExplorationRate() * RANGE_16_BIT_INTEGER_DIVISION_BASIS; + return hashInt < greenbidsConfig.getExplorationRate() * RANGE_16_BIT_INTEGER_DIVISION_BASIS; } private List updateImps(BidRequest bidRequest, Map> impsBiddersFilterMap) { diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/OnnxModelRunnerWithThresholds.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/OnnxModelRunnerWithThresholds.java index adbc1e17b2c..eaa184f7574 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/OnnxModelRunnerWithThresholds.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/OnnxModelRunnerWithThresholds.java @@ -1,7 +1,7 @@ package org.prebid.server.hooks.modules.greenbids.real.time.data.core; import io.vertx.core.Future; -import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.Partner; +import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.GreenbidsConfig; import java.util.Objects; @@ -18,14 +18,14 @@ public OnnxModelRunnerWithThresholds( this.thresholdCache = Objects.requireNonNull(thresholdCache); } - public Future retrieveOnnxModelRunner(Partner partner) { - final String onnxModelPath = "models_pbuid=" + partner.getPbuid() + ".onnx"; - return modelCache.get(onnxModelPath, partner.getPbuid()); + public Future retrieveOnnxModelRunner(GreenbidsConfig greenbidsConfig) { + final String onnxModelPath = "models_pbuid=" + greenbidsConfig.getPbuid() + ".onnx"; + return modelCache.get(onnxModelPath, greenbidsConfig.getPbuid()); } - public Future retrieveThreshold(Partner partner) { - final String thresholdJsonPath = "thresholds_pbuid=" + partner.getPbuid() + ".json"; - return thresholdCache.get(thresholdJsonPath, partner.getPbuid()) - .map(partner::getThreshold); + public Future retrieveThreshold(GreenbidsConfig greenbidsConfig) { + final String thresholdJsonPath = "thresholds_pbuid=" + greenbidsConfig.getPbuid() + ".json"; + return thresholdCache.get(thresholdJsonPath, greenbidsConfig.getPbuid()) + .map(greenbidsConfig::getThreshold); } } diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/Partner.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java similarity index 93% rename from extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/Partner.java rename to extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java index 90e9550b659..babb0f1f930 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/Partner.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java @@ -9,10 +9,7 @@ import java.util.stream.IntStream; @Value(staticConstructor = "of") -public class Partner { - - @JsonProperty(required = true) - Boolean enabled; +public class GreenbidsConfig { String pbuid; diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index 4ce2e8d710d..90b8744529f 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -21,7 +21,7 @@ import org.prebid.server.hooks.modules.greenbids.real.time.data.core.GreenbidsInvocationService; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.OnnxModelRunner; import org.prebid.server.hooks.modules.greenbids.real.time.data.core.OnnxModelRunnerWithThresholds; -import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.Partner; +import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.GreenbidsConfig; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.ThrottlingMessage; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.result.AnalyticsResult; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.result.GreenbidsInvocationResult; @@ -77,27 +77,22 @@ public Future> call( final AuctionContext auctionContext = invocationContext.auctionContext(); final BidRequest bidRequest = auctionContext.getBidRequest(); - final Partner appliedPartner = Optional.ofNullable(parseBidRequestExt(auctionContext)) - .orElse(parseAccountConfig(auctionContext)); - - if (!appliedPartner.getEnabled()) { - return Future.succeededFuture(toInvocationResult( - bidRequest, null, InvocationAction.no_action)); - } + final GreenbidsConfig greenbidsConfig = Optional.ofNullable(parseBidRequestExt(auctionContext)) + .orElse(parseAccountConfig(auctionContext.getAccount())); return Future.all( - onnxModelRunnerWithThresholds.retrieveOnnxModelRunner(appliedPartner), - onnxModelRunnerWithThresholds.retrieveThreshold(appliedPartner)) + onnxModelRunnerWithThresholds.retrieveOnnxModelRunner(greenbidsConfig), + onnxModelRunnerWithThresholds.retrieveThreshold(greenbidsConfig)) .compose(compositeFuture -> toInvocationResult( bidRequest, - appliedPartner, + greenbidsConfig, compositeFuture.resultAt(0), compositeFuture.resultAt(1))) .recover(throwable -> Future.succeededFuture(toInvocationResult( bidRequest, null, InvocationAction.no_action))); } - private Partner parseBidRequestExt(AuctionContext auctionContext) { + private GreenbidsConfig parseBidRequestExt(AuctionContext auctionContext) { return Optional.ofNullable(auctionContext) .map(AuctionContext::getBidRequest) .map(BidRequest::getExt) @@ -105,7 +100,7 @@ private Partner parseBidRequestExt(AuctionContext auctionContext) { .map(ExtRequestPrebid::getAnalytics) .filter(this::isNotEmptyObjectNode) .map(analytics -> (ObjectNode) analytics.get(BID_REQUEST_ANALYTICS_EXTENSION_NAME)) - .map(this::toPartner) + .map(this::toGreenbidsConfig) .orElse(null); } @@ -113,25 +108,18 @@ private boolean isNotEmptyObjectNode(JsonNode analytics) { return analytics != null && analytics.isObject() && !analytics.isEmpty(); } - private Partner parseAccountConfig(AuctionContext auctionContext) { - final Map modules = Optional.ofNullable(auctionContext) - .map(AuctionContext::getAccount) + private GreenbidsConfig parseAccountConfig(Account account) { + return Optional.ofNullable(account) .map(Account::getHooks) .map(AccountHooksConfiguration::getModules) + .map(modules -> modules.get(name())) + .map(this::toGreenbidsConfig) .orElse(null); - - Partner partner = null; - if (modules != null && modules.containsKey("greenbids")) { - final ObjectNode moduleConfig = modules.get("greenbids"); - partner = toPartner(moduleConfig); - } - - return partner; } - private Partner toPartner(ObjectNode adapterNode) { + private GreenbidsConfig toGreenbidsConfig(ObjectNode adapterNode) { try { - return mapper.treeToValue(adapterNode, Partner.class); + return mapper.treeToValue(adapterNode, GreenbidsConfig.class); } catch (JsonProcessingException e) { return null; } @@ -139,7 +127,7 @@ private Partner toPartner(ObjectNode adapterNode) { private Future> toInvocationResult( BidRequest bidRequest, - Partner partner, + GreenbidsConfig greenbidsConfig, OnnxModelRunner onnxModelRunner, Double threshold) { @@ -158,7 +146,7 @@ private Future> toInvocationResult( } final GreenbidsInvocationResult greenbidsInvocationResult = greenbidsInvocationService - .createGreenbidsInvocationResult(partner, bidRequest, impsBiddersFilterMap); + .createGreenbidsInvocationResult(greenbidsConfig, bidRequest, impsBiddersFilterMap); return Future.succeededFuture(toInvocationResult( greenbidsInvocationResult.getUpdatedBidRequest(), @@ -227,4 +215,8 @@ private ObjectNode toObjectNode(Map values) { public String code() { return CODE; } + + public String name() { + return "greenbids"; + } } diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationServiceTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationServiceTest.java index 98b6f59955c..8af8b6e2a03 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationServiceTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationServiceTest.java @@ -10,7 +10,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.analytics.reporter.greenbids.model.Ortb2ImpExtResult; -import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.Partner; +import org.prebid.server.hooks.modules.greenbids.real.time.data.model.data.GreenbidsConfig; import org.prebid.server.hooks.modules.greenbids.real.time.data.model.result.GreenbidsInvocationResult; import org.prebid.server.hooks.v1.InvocationAction; @@ -47,11 +47,11 @@ public void createGreenbidsInvocationResultShouldReturnUpdateBidRequestWhenNotEx final Device device = givenDevice(identity()); final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device); final Map> impsBiddersFilterMap = givenImpsBiddersFilterMap(); - final Partner partner = givenPartner(0.0); + final GreenbidsConfig greenbidsConfig = givenPartner(0.0); // when final GreenbidsInvocationResult result = target.createGreenbidsInvocationResult( - partner, bidRequest, impsBiddersFilterMap); + greenbidsConfig, bidRequest, impsBiddersFilterMap); // then final JsonNode updatedBidRequestExtPrebidBidders = result.getUpdatedBidRequest().getImp().getFirst().getExt() @@ -84,11 +84,11 @@ public void createGreenbidsInvocationResultShouldReturnNoActionWhenExploration() final Device device = givenDevice(identity()); final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device); final Map> impsBiddersFilterMap = givenImpsBiddersFilterMap(); - final Partner partner = givenPartner(1.0); + final GreenbidsConfig greenbidsConfig = givenPartner(1.0); // when final GreenbidsInvocationResult result = target.createGreenbidsInvocationResult( - partner, bidRequest, impsBiddersFilterMap); + greenbidsConfig, bidRequest, impsBiddersFilterMap); // then final JsonNode updatedBidRequestExtPrebidBidders = result.getUpdatedBidRequest().getImp().getFirst().getExt() @@ -120,7 +120,7 @@ private Map> givenImpsBiddersFilterMap() { return impsBiddersFilterMap; } - private Partner givenPartner(Double explorationRate) { - return Partner.of(true, "test-pbuid", 0.60, explorationRate); + private GreenbidsConfig givenPartner(Double explorationRate) { + return GreenbidsConfig.of("test-pbuid", 0.60, explorationRate); } } diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java index 0680a1a53d6..f36c9435e68 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java @@ -26,7 +26,7 @@ import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsAdUnit; import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsAnalyticsProperties; import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsBid; -import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsPrebidExt; +import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsConfig; import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsSource; import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsUnifiedCode; import org.prebid.server.analytics.reporter.greenbids.model.MediaTypes; @@ -120,10 +120,10 @@ public Future processEvent(T event) { return Future.failedFuture(new PreBidException("Bid response or auction context cannot be null")); } - final GreenbidsPrebidExt greenbidsPrebidExt = Optional.ofNullable(parseBidRequestExt(auctionContext)) - .orElse(parseAccountConfig(auctionContext)); + final GreenbidsConfig greenbidsConfig = Optional.ofNullable(parseBidRequestExt(auctionContext)) + .orElse(parseAccountConfig(auctionContext.getAccount())); - if (greenbidsPrebidExt == null) { + if (greenbidsConfig == null) { return Future.succeededFuture(); } @@ -134,7 +134,7 @@ public Future processEvent(T event) { final String greenbidsId = greenbidsId(analyticsResultFromAnalyticsTag); - if (!isSampled(greenbidsPrebidExt.getGreenbidsSampling(), greenbidsId)) { + if (!isSampled(greenbidsConfig.getGreenbidsSampling(), greenbidsId)) { return Future.succeededFuture(); } @@ -145,7 +145,7 @@ public Future processEvent(T event) { bidResponse, greenbidsId, billingId, - greenbidsPrebidExt, + greenbidsConfig, analyticsResultFromAnalyticsTag); commonMessageJson = jacksonMapper.encodeToString(commonMessage); } catch (PreBidException e) { @@ -173,7 +173,7 @@ public Future processEvent(T event) { return responseFuture.compose(this::processAnalyticServerResponse); } - private GreenbidsPrebidExt parseBidRequestExt(AuctionContext auctionContext) { + private GreenbidsConfig parseBidRequestExt(AuctionContext auctionContext) { return Optional.ofNullable(auctionContext) .map(AuctionContext::getBidRequest) .map(BidRequest::getExt) @@ -181,7 +181,7 @@ private GreenbidsPrebidExt parseBidRequestExt(AuctionContext auctionContext) { .map(ExtRequestPrebid::getAnalytics) .filter(this::isNotEmptyObjectNode) .map(analytics -> (ObjectNode) analytics.get(BID_REQUEST_ANALYTICS_EXTENSION_NAME)) - .map(this::toGreenbidsPrebidExt) + .map(this::toGreenbidsConfig) .orElse(null); } @@ -189,25 +189,18 @@ private boolean isNotEmptyObjectNode(JsonNode analytics) { return analytics != null && analytics.isObject() && !analytics.isEmpty(); } - private GreenbidsPrebidExt parseAccountConfig(AuctionContext auctionContext) { - final Map modules = Optional.ofNullable(auctionContext) - .map(AuctionContext::getAccount) + private GreenbidsConfig parseAccountConfig(Account account) { + return Optional.ofNullable(account) .map(Account::getAnalytics) .map(AccountAnalyticsConfig::getModules) + .map(analyticsModules -> analyticsModules.get(name())) + .map(this::toGreenbidsConfig) .orElse(null); - - GreenbidsPrebidExt greenbidsPrebidExt = null; - if (modules != null && modules.containsKey(BID_REQUEST_ANALYTICS_EXTENSION_NAME)) { - final ObjectNode moduleConfig = modules.get(BID_REQUEST_ANALYTICS_EXTENSION_NAME); - greenbidsPrebidExt = toGreenbidsPrebidExt(moduleConfig); - } - - return greenbidsPrebidExt; } - private GreenbidsPrebidExt toGreenbidsPrebidExt(ObjectNode adapterNode) { + private GreenbidsConfig toGreenbidsConfig(ObjectNode adapterNode) { try { - return jacksonMapper.mapper().treeToValue(adapterNode, GreenbidsPrebidExt.class); + return jacksonMapper.mapper().treeToValue(adapterNode, GreenbidsConfig.class); } catch (JsonProcessingException e) { throw new PreBidException("Error decoding bid request analytics extension: " + e.getMessage(), e); } @@ -311,7 +304,7 @@ private CommonMessage createBidMessage( BidResponse bidResponse, String greenbidsId, String billingId, - GreenbidsPrebidExt greenbidsImpExt, + GreenbidsConfig greenbidsImpExt, Map analyticsResultFromAnalyticsTag) { final Optional bidRequest = Optional.ofNullable(auctionContext.getBidRequest()); diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsPrebidExt.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsConfig.java similarity index 82% rename from src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsPrebidExt.java rename to src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsConfig.java index e0ec7e301fa..b666fb83552 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsPrebidExt.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsConfig.java @@ -4,9 +4,7 @@ import lombok.Value; @Value(staticConstructor = "of") -public class GreenbidsPrebidExt { - - Boolean enabled; +public class GreenbidsConfig { String pbuid; From bebb3b3f6ac5d731b6d8a0e687f1e72ae513ddf9 Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Wed, 22 Jan 2025 13:13:18 +0100 Subject: [PATCH 09/13] rebase master --- .../GreenbidsInferenceDataServiceTest.java | 2 +- ...meDataProcessedAuctionRequestHookTest.java | 28 ------------------- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInferenceDataServiceTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInferenceDataServiceTest.java index e355c31d4c7..c56b19e14c2 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInferenceDataServiceTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInferenceDataServiceTest.java @@ -115,7 +115,7 @@ public void extractThrottlingMessagesFromBidRequestShouldReturnValidThrottlingMe .banner(banner) .build(); final Device device = givenDevice(identity(), "FRA"); - 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(); diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java index ece5a6b1407..81ab463c688 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java @@ -389,34 +389,6 @@ public void callShouldFilterBiddersBasedOnModelResults() throws OrtException, IO .isEqualTo(expectedBidRequest); } - static DatabaseReader givenDatabaseReader() throws IOException { - final URL url = new URL("https://git.io/GeoLite2-Country.mmdb"); - final Path databasePath = Files.createTempFile("GeoLite2-Country", ".mmdb"); - - try ( - InputStream inputStream = url.openStream(); - FileOutputStream outputStream = new FileOutputStream(databasePath.toFile())) { - inputStream.transferTo(outputStream); - } - - 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 auctionContextCustomizer, From c62a65e5aff87c8c2bb3ec9af09995c7de10ee16 Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Mon, 27 Jan 2025 12:00:01 +0100 Subject: [PATCH 10/13] fix review: handle npe --- .../data/core/GreenbidsInvocationService.java | 3 +- .../time/data/model/data/GreenbidsConfig.java | 4 ++- ...alTimeDataProcessedAuctionRequestHook.java | 5 +++ .../greenbids/GreenbidsAnalyticsReporter.java | 31 ++++++++++--------- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java index 2b2e615d693..f70e6c4d680 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java @@ -50,9 +50,10 @@ public GreenbidsInvocationResult createGreenbidsInvocationResult( } private Boolean isExploration(GreenbidsConfig greenbidsConfig, String greenbidsId) { + final double explorationRate = Optional.ofNullable(greenbidsConfig.getExplorationRate()).orElse(1.0); final int hashInt = Integer.parseInt( greenbidsId.substring(greenbidsId.length() - 4), 16); - return hashInt < greenbidsConfig.getExplorationRate() * RANGE_16_BIT_INTEGER_DIVISION_BASIS; + return hashInt < explorationRate * RANGE_16_BIT_INTEGER_DIVISION_BASIS; } private List updateImps(BidRequest bidRequest, Map> impsBiddersFilterMap) { diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java index babb0f1f930..b35cfbbdd62 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java @@ -6,6 +6,7 @@ import java.util.Comparator; import java.util.List; +import java.util.Optional; import java.util.stream.IntStream; @Value(staticConstructor = "of") @@ -20,13 +21,14 @@ public class GreenbidsConfig { Double explorationRate; public Double getThreshold(ThrottlingThresholds throttlingThresholds) { + final double safeTargetTpr = Optional.ofNullable(targetTpr).orElse(1.0); final List truePositiveRates = throttlingThresholds.getTpr(); final List thresholds = throttlingThresholds.getThresholds(); final int minSize = Math.min(truePositiveRates.size(), thresholds.size()); return IntStream.range(0, minSize) - .filter(i -> truePositiveRates.get(i) >= targetTpr) + .filter(i -> truePositiveRates.get(i) >= safeTargetTpr) .mapToObj(thresholds::get) .max(Comparator.naturalOrder()) .orElse(0.0); diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index 90b8744529f..100bac46e0e 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -80,6 +80,11 @@ public Future> call( final GreenbidsConfig greenbidsConfig = Optional.ofNullable(parseBidRequestExt(auctionContext)) .orElse(parseAccountConfig(auctionContext.getAccount())); + if (greenbidsConfig == null) { + return Future.failedFuture( + new PreBidException("Greenbids config is null; cannot proceed.")); + } + return Future.all( onnxModelRunnerWithThresholds.retrieveOnnxModelRunner(greenbidsConfig), onnxModelRunnerWithThresholds.retrieveThreshold(greenbidsConfig)) diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java index f36c9435e68..7d4e9eaa988 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java @@ -17,6 +17,7 @@ import io.vertx.core.Future; import io.vertx.core.MultiMap; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.prebid.server.analytics.AnalyticsReporter; import org.prebid.server.analytics.model.AmpEvent; import org.prebid.server.analytics.model.AuctionEvent; @@ -134,7 +135,14 @@ public Future processEvent(T event) { final String greenbidsId = greenbidsId(analyticsResultFromAnalyticsTag); - if (!isSampled(greenbidsConfig.getGreenbidsSampling(), greenbidsId)) { + final double samplingRate = Optional.ofNullable(greenbidsConfig.getGreenbidsSampling()) + .orElseGet(() -> { + logger.warn("Warning: Sampling rate is not defined in request. Set sampling at " + + greenbidsAnalyticsProperties.getDefaultSamplingRate()); + return greenbidsAnalyticsProperties.getDefaultSamplingRate(); + }); + + if (!isSampled(samplingRate, greenbidsId)) { return Future.succeededFuture(); } @@ -146,7 +154,8 @@ public Future processEvent(T event) { greenbidsId, billingId, greenbidsConfig, - analyticsResultFromAnalyticsTag); + analyticsResultFromAnalyticsTag, + samplingRate); commonMessageJson = jacksonMapper.encodeToString(commonMessage); } catch (PreBidException e) { return Future.failedFuture(e); @@ -274,12 +283,6 @@ private Future processAnalyticServerResponse(HttpClientResponse response) } private boolean isSampled(Double samplingRate, String greenbidsId) { - if (samplingRate == null) { - logger.warn("Warning: Sampling rate is not defined in request. Set sampling at " - + greenbidsAnalyticsProperties.getDefaultSamplingRate()); - return true; - } - if (samplingRate < 0 || samplingRate > 1) { logger.warn("Warning: Sampling rate must be between 0 and 1"); return true; @@ -304,8 +307,9 @@ private CommonMessage createBidMessage( BidResponse bidResponse, String greenbidsId, String billingId, - GreenbidsConfig greenbidsImpExt, - Map analyticsResultFromAnalyticsTag) { + GreenbidsConfig greenbidsConfig, + Map analyticsResultFromAnalyticsTag, + Double samplingRate) { final Optional bidRequest = Optional.ofNullable(auctionContext.getBidRequest()); final List imps = bidRequest @@ -337,17 +341,16 @@ private CommonMessage createBidMessage( .map(Site::getPage) .orElse(null); - final Double greenbidsSamplingRate = Optional.ofNullable(greenbidsImpExt.getGreenbidsSampling()) - .orElse(greenbidsAnalyticsProperties.getDefaultSamplingRate()); + final String pbuid = Optional.ofNullable(greenbidsConfig.getPbuid()).orElse(StringUtils.EMPTY); return CommonMessage.builder() .version(greenbidsAnalyticsProperties.getAnalyticsServerVersion()) .auctionId(auctionId) .referrer(referrer) - .sampling(greenbidsSamplingRate) + .sampling(samplingRate) .prebidServer(prebidVersionProvider.getNameVersionRecord()) .greenbidsId(greenbidsId) - .pbuid(greenbidsImpExt.getPbuid()) + .pbuid(pbuid) .billingId(billingId) .adUnits(adUnitsWithBidResponses) .auctionElapsed(auctionElapsed) From b0c5c69b158d240c101396cf283535d41048308f Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Mon, 27 Jan 2025 16:21:26 +0100 Subject: [PATCH 11/13] fix review: minor fixes --- .../data/core/GreenbidsInvocationService.java | 5 ++++- .../time/data/model/data/GreenbidsConfig.java | 4 +++- .../greenbids/GreenbidsAnalyticsReporter.java | 17 +++++++++++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java index f70e6c4d680..47da698c627 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationService.java @@ -22,6 +22,8 @@ public class GreenbidsInvocationService { private static final int RANGE_16_BIT_INTEGER_DIVISION_BASIS = 0x10000; + private static final double DEFAULT_EXPLORATION_RATE = 1.0; + public GreenbidsInvocationResult createGreenbidsInvocationResult( GreenbidsConfig greenbidsConfig, BidRequest bidRequest, @@ -50,7 +52,8 @@ public GreenbidsInvocationResult createGreenbidsInvocationResult( } private Boolean isExploration(GreenbidsConfig greenbidsConfig, String greenbidsId) { - final double explorationRate = Optional.ofNullable(greenbidsConfig.getExplorationRate()).orElse(1.0); + final double explorationRate = Optional.ofNullable(greenbidsConfig.getExplorationRate()) + .orElse(DEFAULT_EXPLORATION_RATE); final int hashInt = Integer.parseInt( greenbidsId.substring(greenbidsId.length() - 4), 16); return hashInt < explorationRate * RANGE_16_BIT_INTEGER_DIVISION_BASIS; diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java index b35cfbbdd62..0b0b37455de 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java @@ -12,6 +12,8 @@ @Value(staticConstructor = "of") public class GreenbidsConfig { + private static final double DEFAULT_TPR = 1.0; + String pbuid; @JsonProperty("targetTpr") @@ -21,7 +23,7 @@ public class GreenbidsConfig { Double explorationRate; public Double getThreshold(ThrottlingThresholds throttlingThresholds) { - final double safeTargetTpr = Optional.ofNullable(targetTpr).orElse(1.0); + final double safeTargetTpr = targetTpr != null ? targetTpr : DEFAULT_TPR; final List truePositiveRates = throttlingThresholds.getTpr(); final List thresholds = throttlingThresholds.getThresholds(); diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java index 7d4e9eaa988..7ca677250a7 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java @@ -135,12 +135,7 @@ public Future processEvent(T event) { final String greenbidsId = greenbidsId(analyticsResultFromAnalyticsTag); - final double samplingRate = Optional.ofNullable(greenbidsConfig.getGreenbidsSampling()) - .orElseGet(() -> { - logger.warn("Warning: Sampling rate is not defined in request. Set sampling at " - + greenbidsAnalyticsProperties.getDefaultSamplingRate()); - return greenbidsAnalyticsProperties.getDefaultSamplingRate(); - }); + final double samplingRate = resolveSamplingRate(greenbidsConfig); if (!isSampled(samplingRate, greenbidsId)) { return Future.succeededFuture(); @@ -274,6 +269,16 @@ private String greenbidsId(Map analyticsResultFromAna .orElseGet(() -> UUID.randomUUID().toString()); } + private double resolveSamplingRate(GreenbidsConfig greenbidsConfig) { + final Double sampling = greenbidsConfig.getGreenbidsSampling(); + if (sampling == null) { + logger.warn("Warning: Sampling rate is not defined in request. Set sampling at {}", + greenbidsAnalyticsProperties.getDefaultSamplingRate()); + return greenbidsAnalyticsProperties.getDefaultSamplingRate(); + } + return sampling; + } + private Future processAnalyticServerResponse(HttpClientResponse response) { final int responseStatusCode = response.getStatusCode(); if (responseStatusCode >= 200 && responseStatusCode < 300) { From e6a10a830360ba5bd302b451f6324741962247ce Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Mon, 27 Jan 2025 17:54:33 +0100 Subject: [PATCH 12/13] fix review: invocationContext.accountConfig --- .../time/data/model/data/GreenbidsConfig.java | 4 +- ...alTimeDataProcessedAuctionRequestHook.java | 15 +++--- ...meDataProcessedAuctionRequestHookTest.java | 47 +++++++++---------- .../greenbids/model/GreenbidsConfig.java | 2 +- .../GreenbidsAnalyticsReporterTest.java | 4 +- 5 files changed, 33 insertions(+), 39 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java index 0b0b37455de..c857dd37e63 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/model/data/GreenbidsConfig.java @@ -16,10 +16,10 @@ public class GreenbidsConfig { String pbuid; - @JsonProperty("targetTpr") + @JsonProperty("target-tpr") Double targetTpr; - @JsonProperty("explorationRate") + @JsonProperty("exploration-rate") Double explorationRate; public Double getThreshold(ThrottlingThresholds throttlingThresholds) { diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index 100bac46e0e..95341fa120d 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -78,7 +78,7 @@ public Future> call( final AuctionContext auctionContext = invocationContext.auctionContext(); final BidRequest bidRequest = auctionContext.getBidRequest(); final GreenbidsConfig greenbidsConfig = Optional.ofNullable(parseBidRequestExt(auctionContext)) - .orElse(parseAccountConfig(auctionContext.getAccount())); + .orElse(parseAccountConfig(invocationContext.accountConfig())); if (greenbidsConfig == null) { return Future.failedFuture( @@ -113,13 +113,12 @@ private boolean isNotEmptyObjectNode(JsonNode analytics) { return analytics != null && analytics.isObject() && !analytics.isEmpty(); } - private GreenbidsConfig parseAccountConfig(Account account) { - return Optional.ofNullable(account) - .map(Account::getHooks) - .map(AccountHooksConfiguration::getModules) - .map(modules -> modules.get(name())) - .map(this::toGreenbidsConfig) - .orElse(null); + private GreenbidsConfig parseAccountConfig(ObjectNode accountConfig) { + try { + return mapper.treeToValue(accountConfig, GreenbidsConfig.class); + } catch (JsonProcessingException e) { + throw new PreBidException(e.getMessage()); + } } private GreenbidsConfig toGreenbidsConfig(ObjectNode adapterNode) { diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java index 81ab463c688..07f13d519f4 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHookTest.java @@ -167,9 +167,9 @@ public void callShouldFilterBiddersWhenPartnerActivatedInBidRequest() final BidRequest bidRequest = givenBidRequestWithExtension(identity(), List.of(imp)); final AuctionContext auctionContext = givenAuctionContext( bidRequest, - context -> context, - explorationRate); - final AuctionInvocationContext invocationContext = givenAuctionInvocationContext(auctionContext); + context -> context); + final AuctionInvocationContext invocationContext = givenAuctionInvocationContext( + auctionContext, explorationRate); when(invocationContext.auctionContext()).thenReturn(auctionContext); when(modelCacheWithExpiration.getIfPresent("onnxModelRunner_test-pbuid")) .thenReturn(givenOnnxModelRunner()); @@ -229,8 +229,9 @@ public void callShouldNotFilterBiddersAndReturnAnalyticsTagWhenExploration() thr final Double explorationRate = 1.0; final Device device = givenDevice(identity()); final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device); - final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context, explorationRate); - final AuctionInvocationContext invocationContext = givenAuctionInvocationContext(auctionContext); + final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context); + final AuctionInvocationContext invocationContext = givenAuctionInvocationContext( + auctionContext, explorationRate); when(invocationContext.auctionContext()).thenReturn(auctionContext); when(modelCacheWithExpiration.getIfPresent("onnxModelRunner_test-pbuid")) .thenReturn(givenOnnxModelRunner()); @@ -282,8 +283,9 @@ public void callShouldFilterBiddersBasedOnModelWhenAnyFeatureNotAvailable() thro final Double explorationRate = 0.0001; final Device device = givenDeviceWithoutUserAgent(identity()); final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device); - final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context, explorationRate); - final AuctionInvocationContext invocationContext = givenAuctionInvocationContext(auctionContext); + final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context); + final AuctionInvocationContext invocationContext = givenAuctionInvocationContext( + auctionContext, explorationRate); when(invocationContext.auctionContext()).thenReturn(auctionContext); when(modelCacheWithExpiration.getIfPresent("onnxModelRunner_test-pbuid")) .thenReturn(givenOnnxModelRunner()); @@ -342,8 +344,9 @@ public void callShouldFilterBiddersBasedOnModelResults() throws OrtException, IO final Double explorationRate = 0.0001; final Device device = givenDevice(identity()); final BidRequest bidRequest = givenBidRequest(request -> request, List.of(imp), device); - final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context, explorationRate); - final AuctionInvocationContext invocationContext = givenAuctionInvocationContext(auctionContext); + final AuctionContext auctionContext = givenAuctionContext(bidRequest, context -> context); + final AuctionInvocationContext invocationContext = givenAuctionInvocationContext( + auctionContext, explorationRate); when(invocationContext.auctionContext()).thenReturn(auctionContext); when(modelCacheWithExpiration.getIfPresent("onnxModelRunner_test-pbuid")) .thenReturn(givenOnnxModelRunner()); @@ -391,38 +394,30 @@ public void callShouldFilterBiddersBasedOnModelResults() throws OrtException, IO private AuctionContext givenAuctionContext( BidRequest bidRequest, - UnaryOperator auctionContextCustomizer, - Double explorationRate) { + UnaryOperator auctionContextCustomizer) { final AuctionContext.AuctionContextBuilder auctionContextBuilder = AuctionContext.builder() .httpRequest(HttpRequestContext.builder().build()) - .bidRequest(bidRequest) - .account(givenAccount(explorationRate)); + .bidRequest(bidRequest); return auctionContextCustomizer.apply(auctionContextBuilder).build(); } - private AuctionInvocationContext givenAuctionInvocationContext(AuctionContext auctionContext) { + private AuctionInvocationContext givenAuctionInvocationContext( + AuctionContext auctionContext, Double explorationRate) { final AuctionInvocationContext invocationContext = mock(AuctionInvocationContext.class); when(invocationContext.auctionContext()).thenReturn(auctionContext); + when(invocationContext.accountConfig()).thenReturn(givenAccountConfig(explorationRate)); return invocationContext; } - private Account givenAccount(Double explorationRate) { - return Account.builder() - .id("test-account") - .hooks(givenAccountHooksConfiguration(explorationRate)) - .build(); - } - - private AccountHooksConfiguration givenAccountHooksConfiguration(Double explorationRate) { + private ObjectNode givenAccountConfig(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 modules = Map.of("greenbids", greenbidsNode); - return AccountHooksConfiguration.of(null, modules, null); + greenbidsNode.put("target-tpr", 0.60); + greenbidsNode.put("exploration-rate", explorationRate); + return greenbidsNode; } private OnnxModelRunner givenOnnxModelRunner() throws OrtException, IOException { diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsConfig.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsConfig.java index b666fb83552..2820daea092 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsConfig.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/model/GreenbidsConfig.java @@ -8,6 +8,6 @@ public class GreenbidsConfig { String pbuid; - @JsonProperty("greenbidsSampling") + @JsonProperty("greenbids-sampling") Double greenbidsSampling; } diff --git a/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java b/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java index 0093862d936..82cae87406e 100644 --- a/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java +++ b/src/test/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporterTest.java @@ -668,7 +668,7 @@ private static Account givenAccount() { private static AccountAnalyticsConfig givenAccountHooksConfiguration() { final ObjectNode greenbidsNode = mapper.createObjectNode(); greenbidsNode.put("pbuid", "leparisien"); - greenbidsNode.put("greenbidsSampling", 1.0); + greenbidsNode.put("greenbids-sampling", 1.0); final Map modules = Map.of("greenbids", greenbidsNode); return AccountAnalyticsConfig.of(true, null, modules); } @@ -701,7 +701,7 @@ private static BidRequest givenBidRequestWithExtension( private static ExtRequest givenExtRequest() { final ObjectNode greenbidsNode = new ObjectMapper().createObjectNode(); greenbidsNode.put("pbuid", "leparisien"); - greenbidsNode.put("greenbidsSampling", 1.0); + greenbidsNode.put("greenbids-sampling", 1.0); final ObjectNode analyticsNode = new ObjectMapper().createObjectNode(); analyticsNode.set("greenbids", greenbidsNode); From 010e003dd62780529b31c36c22c41bf224069899 Mon Sep 17 00:00:00 2001 From: EvgeniiMunin Date: Wed, 29 Jan 2025 15:58:42 +0100 Subject: [PATCH 13/13] fix review: fmt fixes --- ...ealTimeDataProcessedAuctionRequestHook.java | 18 +++--------------- .../greenbids/GreenbidsAnalyticsReporter.java | 2 +- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index 95341fa120d..5188b756ddc 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -78,7 +78,7 @@ public Future> call( final AuctionContext auctionContext = invocationContext.auctionContext(); final BidRequest bidRequest = auctionContext.getBidRequest(); final GreenbidsConfig greenbidsConfig = Optional.ofNullable(parseBidRequestExt(auctionContext)) - .orElse(parseAccountConfig(invocationContext.accountConfig())); + .orElseGet(() -> toGreenbidsConfig(invocationContext.accountConfig())); if (greenbidsConfig == null) { return Future.failedFuture( @@ -113,17 +113,9 @@ private boolean isNotEmptyObjectNode(JsonNode analytics) { return analytics != null && analytics.isObject() && !analytics.isEmpty(); } - private GreenbidsConfig parseAccountConfig(ObjectNode accountConfig) { + private GreenbidsConfig toGreenbidsConfig(ObjectNode greenbidsConfigNode) { try { - return mapper.treeToValue(accountConfig, GreenbidsConfig.class); - } catch (JsonProcessingException e) { - throw new PreBidException(e.getMessage()); - } - } - - private GreenbidsConfig toGreenbidsConfig(ObjectNode adapterNode) { - try { - return mapper.treeToValue(adapterNode, GreenbidsConfig.class); + return mapper.treeToValue(greenbidsConfigNode, GreenbidsConfig.class); } catch (JsonProcessingException e) { return null; } @@ -219,8 +211,4 @@ private ObjectNode toObjectNode(Map values) { public String code() { return CODE; } - - public String name() { - return "greenbids"; - } } diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java index 7ca677250a7..d4b0a4f8711 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java @@ -122,7 +122,7 @@ public Future processEvent(T event) { } final GreenbidsConfig greenbidsConfig = Optional.ofNullable(parseBidRequestExt(auctionContext)) - .orElse(parseAccountConfig(auctionContext.getAccount())); + .orElseGet(() -> parseAccountConfig(auctionContext.getAccount())); if (greenbidsConfig == null) { return Future.succeededFuture();