From bf8c1fa7d65b0cfef4721c3f4c592471acfce06a Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Fri, 25 Apr 2025 15:18:37 +0200 Subject: [PATCH 01/34] WIP - LiveIntent Module --- extra/bundle/pom.xml | 5 ++ .../live-intent-omni-channel-identity/pom.xml | 17 ++++ ...ntentOmniChannelIdentityConfiguration.java | 34 ++++++++ .../channel/identity/model/IdResResponse.java | 13 +++ .../identity/model/config/ModuleConfig.java | 9 ++ .../LiveIntentOmniChannelIdentityModule.java | 23 +++++ ...elIdentityProcessedAuctionRequestHook.java | 86 +++++++++++++++++++ extra/modules/pom.xml | 1 + 8 files changed, 188 insertions(+) create mode 100644 extra/modules/live-intent-omni-channel-identity/pom.xml create mode 100644 extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java create mode 100644 extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java create mode 100644 extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java create mode 100644 extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java create mode 100644 extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java diff --git a/extra/bundle/pom.xml b/extra/bundle/pom.xml index ce5b002df4b..d589f218121 100644 --- a/extra/bundle/pom.xml +++ b/extra/bundle/pom.xml @@ -55,6 +55,11 @@ pb-request-correction ${project.version} + + org.prebid.server.hooks.modules + live-intent-omni-channel-identity + ${project.version} + diff --git a/extra/modules/live-intent-omni-channel-identity/pom.xml b/extra/modules/live-intent-omni-channel-identity/pom.xml new file mode 100644 index 00000000000..5263d29fd21 --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + org.prebid.server.hooks.modules + all-modules + 3.24.0-SNAPSHOT + + + live-intent-omni-channel-identity + + live-intent-omni-channel-identity + LiveIntent Omni-Channel Identity + + + + diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java new file mode 100644 index 00000000000..183b037fd27 --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -0,0 +1,34 @@ +package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.config; + +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.ModuleConfig; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1.LiveIntentOmniChannelIdentityModule; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1.hooks.LiveIntentOmniChannelIdentityProcessedAuctionRequestHook; +import org.prebid.server.hooks.v1.Hook; +import org.prebid.server.hooks.v1.InvocationContext; +import org.prebid.server.hooks.v1.Module; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.vertx.httpclient.HttpClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Set; + +@Configuration +@ConditionalOnProperty(prefix = "hooks." + LiveIntentOmniChannelIdentityModule.CODE, name = "enabled", havingValue = "true") +public class LiveIntentOmniChannelIdentityConfiguration { + @Bean + @ConfigurationProperties(prefix = "hooks.modules." + LiveIntentOmniChannelIdentityModule.CODE) + ModuleConfig moduleConfig() { + return new ModuleConfig(); + } + + @Bean + Module liveIntentOmniChannelIdentityModule(ModuleConfig config, JacksonMapper mapper, HttpClient httpClient) { + final Set> hooks = Set.of( + new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(config, mapper, httpClient) + ); + return new LiveIntentOmniChannelIdentityModule(hooks); + } +} diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java new file mode 100644 index 00000000000..9be5994dc52 --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java @@ -0,0 +1,13 @@ +package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model; + +import com.iab.openrtb.request.Eid; +import lombok.Builder; +import lombok.Value; + +import java.util.List; + +@Value +@Builder(toBuilder = true) +public class IdResResponse { + List eids; +} diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java new file mode 100644 index 00000000000..6e55fc55fb2 --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java @@ -0,0 +1,9 @@ +package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config; + +import lombok.Data; + +@Data +public final class ModuleConfig { + Long requestTimeout; + String idResUrl; +} diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java new file mode 100644 index 00000000000..b0c90dbb9f1 --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java @@ -0,0 +1,23 @@ +package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1; + +import org.prebid.server.hooks.v1.Hook; +import org.prebid.server.hooks.v1.InvocationContext; +import org.prebid.server.hooks.v1.Module; + +import java.util.Collection; + +public record LiveIntentOmniChannelIdentityModule ( + Collection> hooks +) implements Module { + public static final String CODE = "liveintent-omni-channel-identity"; + + @Override + public String code() { + return CODE; + } + + @Override + public Collection> hooks() { + return hooks; + } +} diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java new file mode 100644 index 00000000000..7d8a9b4c970 --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -0,0 +1,86 @@ +package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1.hooks; + +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Eid; +import com.iab.openrtb.request.User; +import io.vertx.core.Future; +import org.prebid.server.hooks.execution.v1.InvocationResultImpl; +import org.prebid.server.hooks.execution.v1.auction.AuctionRequestPayloadImpl; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.IdResResponse; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.ModuleConfig; +import org.prebid.server.hooks.v1.InvocationAction; +import org.prebid.server.hooks.v1.InvocationResult; +import org.prebid.server.hooks.v1.InvocationStatus; +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.json.JacksonMapper; +import org.prebid.server.vertx.httpclient.HttpClient; +import org.prebid.server.vertx.httpclient.model.HttpClientResponse; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { + + private static final String CODE = "liveintent-enrichment-hook"; + + private final ModuleConfig config; + private final JacksonMapper mapper; + private final HttpClient httpClient; + + public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( + ModuleConfig config, + JacksonMapper mapper, + HttpClient httpClient) { + this.config = Objects.requireNonNull(config); + this.mapper = Objects.requireNonNull(mapper); + this.httpClient = Objects.requireNonNull(httpClient); + } + + // TODO: Error handling + @Override + public Future> call(AuctionRequestPayload auctionRequestPayload, AuctionInvocationContext invocationContext) { + return requestEnrichment(auctionRequestPayload) + .map(resolutionResult -> + InvocationResultImpl.builder() + .status(InvocationStatus.success) + .action(InvocationAction.update) + .payloadUpdate(requestPayload -> updatedPayload(requestPayload, resolutionResult)) + .build() + ); + } + + @Override + public String code() { + return CODE; + } + + private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayload, IdResResponse idResResponse) { + BidRequest bidRequest = requestPayload.bidRequest(); + User user = bidRequest.getUser(); + + List allEids = new ArrayList<>(); + allEids.addAll(user.getEids()); + allEids.addAll(idResResponse.getEids()); + + User updatedUser = user.toBuilder().eids(allEids).build(); + BidRequest updatedBidRequest = requestPayload.bidRequest().toBuilder().user(updatedUser).build(); + + return AuctionRequestPayloadImpl.of(updatedBidRequest); + } + + private Future requestEnrichment(AuctionRequestPayload auctionRequestPayload) { + String bidRequestJson = mapper.encodeToString(auctionRequestPayload.bidRequest()); + return httpClient.post( + config.getIdResUrl(), + bidRequestJson, + config.getRequestTimeout()) + .map(this::processResponse); + } + + private IdResResponse processResponse(HttpClientResponse response) { + return mapper.decodeValue(response.getBody(), IdResResponse.class); + } +} diff --git a/extra/modules/pom.xml b/extra/modules/pom.xml index 0d5de3c0a5e..332b10c9c25 100644 --- a/extra/modules/pom.xml +++ b/extra/modules/pom.xml @@ -24,6 +24,7 @@ pb-response-correction greenbids-real-time-data pb-request-correction + live-intent-omni-channel-identity From 8429f34781b088123ebeef43db87213919656810 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Fri, 25 Apr 2025 15:29:13 +0200 Subject: [PATCH 02/34] Adjust the hook code --- ...iveIntentOmniChannelIdentityProcessedAuctionRequestHook.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 7d8a9b4c970..425798673ed 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -24,7 +24,7 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { - private static final String CODE = "liveintent-enrichment-hook"; + private static final String CODE = "liveintent-omni-channel-identity-enrichment-hook"; private final ModuleConfig config; private final JacksonMapper mapper; From 459028de8da346fef2b0bc6cb1ab99e30be35d72 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Fri, 25 Apr 2025 15:46:06 +0200 Subject: [PATCH 03/34] WIP - polish, add config tests --- .../identity/model/config/ModuleConfig.java | 4 ++-- ...elIdentityProcessedAuctionRequestHook.java | 6 +++--- .../model/config/ModuleConfigTest.java | 21 +++++++++++++++++++ 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java index 6e55fc55fb2..f106ac56111 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java @@ -4,6 +4,6 @@ @Data public final class ModuleConfig { - Long requestTimeout; - String idResUrl; + long requestTimeoutMs; + String identityResolutionEndpoint; } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 425798673ed..23f4b78c7a3 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -39,7 +39,7 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( this.httpClient = Objects.requireNonNull(httpClient); } - // TODO: Error handling + // TODO: Caching @Override public Future> call(AuctionRequestPayload auctionRequestPayload, AuctionInvocationContext invocationContext) { return requestEnrichment(auctionRequestPayload) @@ -74,9 +74,9 @@ private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayloa private Future requestEnrichment(AuctionRequestPayload auctionRequestPayload) { String bidRequestJson = mapper.encodeToString(auctionRequestPayload.bidRequest()); return httpClient.post( - config.getIdResUrl(), + config.getIdentityResolutionEndpoint(), bidRequestJson, - config.getRequestTimeout()) + config.getRequestTimeoutMs()) .map(this::processResponse); } diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java new file mode 100644 index 00000000000..b71c66be20b --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java @@ -0,0 +1,21 @@ +package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ModuleConfigTest { + @Test + public void shouldReturnRequestTimeoutMs() { + ModuleConfig moduleConfig = new ModuleConfig(); + moduleConfig.setRequestTimeoutMs(5); + assertThat(moduleConfig.getRequestTimeoutMs()).isEqualTo(5); + } + + @Test + public void shouldReturnIdentityResolutionEndpoint() { + ModuleConfig moduleConfig = new ModuleConfig(); + moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); + assertThat(moduleConfig.getIdentityResolutionEndpoint()).isEqualTo("https://test.com/idres"); + } +} From c846d1c9721f8f598e11f963a351ef7e56c1ccfe Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Mon, 28 Apr 2025 13:38:04 +0200 Subject: [PATCH 04/34] Add unit tests --- .../live-intent-omni-channel-identity/pom.xml | 2 +- .../channel/identity/model/IdResResponse.java | 10 +- .../LiveIntentOmniChannelIdentityModule.java | 5 +- ...elIdentityProcessedAuctionRequestHook.java | 7 +- ...entityProcessedAuctionRequestHookTest.java | 113 ++++++++++++++++++ 5 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java diff --git a/extra/modules/live-intent-omni-channel-identity/pom.xml b/extra/modules/live-intent-omni-channel-identity/pom.xml index 5263d29fd21..d1bf2a08aff 100644 --- a/extra/modules/live-intent-omni-channel-identity/pom.xml +++ b/extra/modules/live-intent-omni-channel-identity/pom.xml @@ -4,7 +4,7 @@ org.prebid.server.hooks.modules all-modules - 3.24.0-SNAPSHOT + 3.25.0-SNAPSHOT live-intent-omni-channel-identity diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java index 9be5994dc52..0e72f5763ce 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java @@ -1,13 +1,17 @@ package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model; +import com.fasterxml.jackson.annotation.JsonProperty; import com.iab.openrtb.request.Eid; import lombok.Builder; -import lombok.Value; +import lombok.Data; +import lombok.extern.jackson.Jacksonized; import java.util.List; -@Value -@Builder(toBuilder = true) +@Builder +@Data +@Jacksonized public class IdResResponse { + @JsonProperty("eids") List eids; } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java index b0c90dbb9f1..9890c85e695 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java @@ -6,9 +6,8 @@ import java.util.Collection; -public record LiveIntentOmniChannelIdentityModule ( - Collection> hooks -) implements Module { +public record LiveIntentOmniChannelIdentityModule(Collection> hooks) implements Module { + public static final String CODE = "liveintent-omni-channel-identity"; @Override diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 23f4b78c7a3..129689c32b9 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { @@ -58,11 +59,11 @@ public String code() { } private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayload, IdResResponse idResResponse) { - BidRequest bidRequest = requestPayload.bidRequest(); - User user = bidRequest.getUser(); + BidRequest bidRequest = Optional.ofNullable(requestPayload.bidRequest()).orElse(BidRequest.builder().build()); + User user = Optional.ofNullable(bidRequest.getUser()).orElse(User.builder().build()); List allEids = new ArrayList<>(); - allEids.addAll(user.getEids()); + allEids.addAll(Optional.ofNullable(user.getEids()).orElse(List.of())); allEids.addAll(idResResponse.getEids()); User updatedUser = user.toBuilder().eids(allEids).build(); diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java new file mode 100644 index 00000000000..1fccc6d79eb --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -0,0 +1,113 @@ +package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Eid; +import com.iab.openrtb.request.Uid; +import com.iab.openrtb.request.User; +import io.vertx.core.Future; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.prebid.server.hooks.execution.v1.auction.AuctionInvocationContextImpl; +import org.prebid.server.hooks.execution.v1.auction.AuctionRequestPayloadImpl; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.ModuleConfig; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1.hooks.LiveIntentOmniChannelIdentityProcessedAuctionRequestHook; +import org.prebid.server.hooks.v1.InvocationAction; +import org.prebid.server.hooks.v1.InvocationResult; +import org.prebid.server.hooks.v1.InvocationStatus; +import org.prebid.server.hooks.v1.auction.AuctionInvocationContext; +import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.vertx.httpclient.HttpClient; +import org.prebid.server.vertx.httpclient.model.HttpClientResponse; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest { + + private ModuleConfig moduleConfig; + private LiveIntentOmniChannelIdentityProcessedAuctionRequestHook target; + private JacksonMapper jacksonMapper; + + + @BeforeEach + public void setUp() { + ObjectMapper mapper = new ObjectMapper(); + jacksonMapper = new JacksonMapper(mapper); + + moduleConfig = new ModuleConfig(); + moduleConfig.setRequestTimeoutMs(5); + moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); + + target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(moduleConfig, jacksonMapper, httpClient); + } + + @Mock + private HttpClient httpClient; + + @Test + public void shouldAddResolvedEids() { + Uid providedUid = Uid.builder().id("id1").atype(2).build(); + Eid providedEid = Eid.builder().source("some.source.com").uids(List.of(providedUid)).build(); + + Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); + Eid enrichedEid = Eid.builder().source("liveintent.com").uids(List.of(enrichedUid)).build(); + + User user = User.builder().eids(List.of(providedEid)).build(); + BidRequest bidRequest = BidRequest.builder().id("request").user(user).build(); + + AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); + + HttpClientResponse mockResponse = mock(HttpClientResponse.class); + when(mockResponse.getBody()).thenReturn("{\"eids\": [ { \"source\": \""+ enrichedEid.getSource() + "\", \"uids\": [ { \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" } ] } ] }"); + + when(httpClient.post(moduleConfig.getIdentityResolutionEndpoint(), jacksonMapper.encodeToString(bidRequest), moduleConfig.getRequestTimeoutMs())) + .thenReturn(Future.succeededFuture(mockResponse)); + + Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); + InvocationResult result = future.result(); + + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull(); + assertThat(result.status()).isEqualTo(InvocationStatus.success); + assertThat(result.action()).isEqualTo(InvocationAction.update); + assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(List.of(providedEid, enrichedEid)); + } + + @Test + public void shouldCreateUserWhenNotPresent() { + Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); + Eid enrichedEid = Eid.builder().source("liveintent.com").uids(List.of(enrichedUid)).build(); + + BidRequest bidRequest = BidRequest.builder().id("request").build(); + + AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); + + HttpClientResponse mockResponse = mock(HttpClientResponse.class); + when(mockResponse.getBody()).thenReturn("{\"eids\": [{ \"source\": \""+ enrichedEid.getSource() + "\", \"uids\": [{ \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" }]}]}"); + + when(httpClient.post(moduleConfig.getIdentityResolutionEndpoint(), jacksonMapper.encodeToString(bidRequest), moduleConfig.getRequestTimeoutMs())) + .thenReturn(Future.succeededFuture(mockResponse)); + + Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); + InvocationResult result = future.result(); + + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull(); + assertThat(result.status()).isEqualTo(InvocationStatus.success); + assertThat(result.action()).isEqualTo(InvocationAction.update); + assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(List.of(enrichedEid)); + } +} From 8348d4655da3523f0ffe6070aa5743318974fb97 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Tue, 29 Apr 2025 15:51:31 +0200 Subject: [PATCH 05/34] Add auth token --- ...ntentOmniChannelIdentityConfiguration.java | 4 +- .../identity/model/config/ModuleConfig.java | 1 + ...elIdentityProcessedAuctionRequestHook.java | 9 ++++ .../model/config/ModuleConfigTest.java | 7 +++ ...entityProcessedAuctionRequestHookTest.java | 51 +++++++++++++++---- 5 files changed, 58 insertions(+), 14 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index 183b037fd27..aabc80d852f 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -20,9 +20,7 @@ public class LiveIntentOmniChannelIdentityConfiguration { @Bean @ConfigurationProperties(prefix = "hooks.modules." + LiveIntentOmniChannelIdentityModule.CODE) - ModuleConfig moduleConfig() { - return new ModuleConfig(); - } + ModuleConfig moduleConfig() {return new ModuleConfig();} @Bean Module liveIntentOmniChannelIdentityModule(ModuleConfig config, JacksonMapper mapper, HttpClient httpClient) { diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java index f106ac56111..cf35c8e9211 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java @@ -6,4 +6,5 @@ public final class ModuleConfig { long requestTimeoutMs; String identityResolutionEndpoint; + String authToken; } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 129689c32b9..1bed1267e22 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -3,7 +3,9 @@ import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Eid; import com.iab.openrtb.request.User; +import io.netty.handler.codec.http.HttpHeaderValues; import io.vertx.core.Future; +import io.vertx.core.MultiMap; import org.prebid.server.hooks.execution.v1.InvocationResultImpl; import org.prebid.server.hooks.execution.v1.auction.AuctionRequestPayloadImpl; import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.IdResResponse; @@ -15,6 +17,7 @@ import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; import org.prebid.server.hooks.v1.auction.ProcessedAuctionRequestHook; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.util.HttpUtil; import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; @@ -76,6 +79,7 @@ private Future requestEnrichment(AuctionRequestPayload auctionReq String bidRequestJson = mapper.encodeToString(auctionRequestPayload.bidRequest()); return httpClient.post( config.getIdentityResolutionEndpoint(), + headers(), bidRequestJson, config.getRequestTimeoutMs()) .map(this::processResponse); @@ -84,4 +88,9 @@ private Future requestEnrichment(AuctionRequestPayload auctionReq private IdResResponse processResponse(HttpClientResponse response) { return mapper.decodeValue(response.getBody(), IdResResponse.class); } + + private MultiMap headers() { + return MultiMap.caseInsensitiveMultiMap() + .add(HttpUtil.AUTHORIZATION_HEADER, "Bearer " + config.getAuthToken()); + } } diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java index b71c66be20b..1fa4860b023 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java @@ -18,4 +18,11 @@ public void shouldReturnIdentityResolutionEndpoint() { moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); assertThat(moduleConfig.getIdentityResolutionEndpoint()).isEqualTo("https://test.com/idres"); } + + @Test + public void shouldReturnAuthToken() { + ModuleConfig moduleConfig = new ModuleConfig(); + moduleConfig.setAuthToken("secret_token"); + assertThat(moduleConfig.getAuthToken()).isEqualTo("secret_token"); + } } diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index 1fccc6d79eb..155746a1e54 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -6,9 +6,11 @@ import com.iab.openrtb.request.Uid; import com.iab.openrtb.request.User; import io.vertx.core.Future; +import io.vertx.core.MultiMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.hooks.execution.v1.auction.AuctionInvocationContextImpl; @@ -21,14 +23,19 @@ import org.prebid.server.hooks.v1.auction.AuctionInvocationContext; import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.util.HttpUtil; import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; import java.util.List; +import java.util.function.Consumer; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.assertArg; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -39,7 +46,6 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest { private LiveIntentOmniChannelIdentityProcessedAuctionRequestHook target; private JacksonMapper jacksonMapper; - @BeforeEach public void setUp() { ObjectMapper mapper = new ObjectMapper(); @@ -48,6 +54,7 @@ public void setUp() { moduleConfig = new ModuleConfig(); moduleConfig.setRequestTimeoutMs(5); moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); + moduleConfig.setAuthToken("secret_auth_token"); target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(moduleConfig, jacksonMapper, httpClient); } @@ -69,10 +76,21 @@ public void shouldAddResolvedEids() { AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); HttpClientResponse mockResponse = mock(HttpClientResponse.class); - when(mockResponse.getBody()).thenReturn("{\"eids\": [ { \"source\": \""+ enrichedEid.getSource() + "\", \"uids\": [ { \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" } ] } ] }"); - - when(httpClient.post(moduleConfig.getIdentityResolutionEndpoint(), jacksonMapper.encodeToString(bidRequest), moduleConfig.getRequestTimeoutMs())) - .thenReturn(Future.succeededFuture(mockResponse)); + when(mockResponse.getBody()).thenReturn("{\"eids\": [ { \"source\": \"" + enrichedEid.getSource() + "\", \"uids\": [ { \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" } ] } ] }"); + + when( + httpClient.post( + eq(moduleConfig.getIdentityResolutionEndpoint()), + argThat(new ArgumentMatcher() { + @Override + public boolean matches(MultiMap entries) { + return entries.contains("Authorization", "Bearer " + moduleConfig.getAuthToken(), true); + } + }), + eq(jacksonMapper.encodeToString(bidRequest)), + eq(moduleConfig.getRequestTimeoutMs()) + ) + ).thenReturn(Future.succeededFuture(mockResponse)); Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); InvocationResult result = future.result(); @@ -95,10 +113,21 @@ public void shouldCreateUserWhenNotPresent() { AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); HttpClientResponse mockResponse = mock(HttpClientResponse.class); - when(mockResponse.getBody()).thenReturn("{\"eids\": [{ \"source\": \""+ enrichedEid.getSource() + "\", \"uids\": [{ \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" }]}]}"); - - when(httpClient.post(moduleConfig.getIdentityResolutionEndpoint(), jacksonMapper.encodeToString(bidRequest), moduleConfig.getRequestTimeoutMs())) - .thenReturn(Future.succeededFuture(mockResponse)); + when(mockResponse.getBody()).thenReturn("{\"eids\": [{ \"source\": \"" + enrichedEid.getSource() + "\", \"uids\": [{ \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" }]}]}"); + + when( + httpClient.post( + eq(moduleConfig.getIdentityResolutionEndpoint()), + argThat(new ArgumentMatcher() { + @Override + public boolean matches(MultiMap entries) { + return entries.contains("Authorization", "Bearer " + moduleConfig.getAuthToken(), true); + } + }), + eq(jacksonMapper.encodeToString(bidRequest)), + eq(moduleConfig.getRequestTimeoutMs()) + ) + ).thenReturn(Future.succeededFuture(mockResponse)); Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); InvocationResult result = future.result(); From c0f656671640acccc15dc51cb62c76bb5459d1ad Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Tue, 6 May 2025 13:47:47 +0200 Subject: [PATCH 06/34] Add README.md --- .../README.md | 43 +++++++++++++++++++ ...elIdentityProcessedAuctionRequestHook.java | 2 - 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 extra/modules/live-intent-omni-channel-identity/README.md diff --git a/extra/modules/live-intent-omni-channel-identity/README.md b/extra/modules/live-intent-omni-channel-identity/README.md new file mode 100644 index 00000000000..3fbdba78b71 --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/README.md @@ -0,0 +1,43 @@ +# Overview + +This module enriches bid requests with user IDs that it adds to the user EIDs. + +The user IDs to be enriched are configured on LiveIntent's side. The set of user IDs accessible by a partner are determined by the auth token provided in the settings. + +## Configuration +To start using the LiveIntent Omni Channel Identity module you have to enable it and add configuration: + +```yaml +hooks: + liveintent-omni-channel-identity: + enabled: true + host-execution-plan: > + { + "endpoints": { + "/openrtb2/auction": { + "stages": { + "all-processed-bid-responses": { + "groups": [ + { + "timeout": 100, + "hook-sequence": [ + { + "module-code": "liveintent-omni-channel-identity", + "hook-impl-code": "liveintent-omni-channel-identity-enrichment-hook" + } + ] + } + ] + } + } + } + } + } + modules: + liveintent-omni-channel-identity: + request-timeout-ms: 2000 + identity-resolution-endpoint: "https://liveintent.com/idx" + auth-token: "secret-token" +``` + + diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 1bed1267e22..44da5735acd 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -3,7 +3,6 @@ import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Eid; import com.iab.openrtb.request.User; -import io.netty.handler.codec.http.HttpHeaderValues; import io.vertx.core.Future; import io.vertx.core.MultiMap; import org.prebid.server.hooks.execution.v1.InvocationResultImpl; @@ -43,7 +42,6 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( this.httpClient = Objects.requireNonNull(httpClient); } - // TODO: Caching @Override public Future> call(AuctionRequestPayload auctionRequestPayload, AuctionInvocationContext invocationContext) { return requestEnrichment(auctionRequestPayload) From 4f90c177df1dac03368dbda391300601f28daedc Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Tue, 6 May 2025 15:33:37 +0200 Subject: [PATCH 07/34] Fix stage --- extra/modules/live-intent-omni-channel-identity/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/modules/live-intent-omni-channel-identity/README.md b/extra/modules/live-intent-omni-channel-identity/README.md index 3fbdba78b71..526da24fe9a 100644 --- a/extra/modules/live-intent-omni-channel-identity/README.md +++ b/extra/modules/live-intent-omni-channel-identity/README.md @@ -16,7 +16,7 @@ hooks: "endpoints": { "/openrtb2/auction": { "stages": { - "all-processed-bid-responses": { + "processed-auction-request": { "groups": [ { "timeout": 100, From c6dc20e644ee907d5dbd1286b78d452d79679fd8 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 7 May 2025 10:06:11 +0200 Subject: [PATCH 08/34] Add logging --- ...iveIntentOmniChannelIdentityConfiguration.java | 6 ++++-- .../v1/LiveIntentOmniChannelIdentityModule.java | 3 ++- ...hannelIdentityProcessedAuctionRequestHook.java | 15 ++++++++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index aabc80d852f..0bc46332f3c 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -20,12 +20,14 @@ public class LiveIntentOmniChannelIdentityConfiguration { @Bean @ConfigurationProperties(prefix = "hooks.modules." + LiveIntentOmniChannelIdentityModule.CODE) - ModuleConfig moduleConfig() {return new ModuleConfig();} + ModuleConfig moduleConfig() { + return new ModuleConfig(); + } @Bean Module liveIntentOmniChannelIdentityModule(ModuleConfig config, JacksonMapper mapper, HttpClient httpClient) { final Set> hooks = Set.of( - new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(config, mapper, httpClient) + new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(config, mapper, httpClient) ); return new LiveIntentOmniChannelIdentityModule(hooks); } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java index 9890c85e695..0ffdce8b436 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityModule.java @@ -6,7 +6,8 @@ import java.util.Collection; -public record LiveIntentOmniChannelIdentityModule(Collection> hooks) implements Module { +public record LiveIntentOmniChannelIdentityModule( + Collection> hooks) implements Module { public static final String CODE = "liveintent-omni-channel-identity"; diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 44da5735acd..de0720c59c8 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -16,6 +16,8 @@ import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; import org.prebid.server.hooks.v1.auction.ProcessedAuctionRequestHook; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.log.Logger; +import org.prebid.server.log.LoggerFactory; import org.prebid.server.util.HttpUtil; import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; @@ -27,6 +29,7 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { + private static final Logger logger = LoggerFactory.getLogger(LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.class); private static final String CODE = "liveintent-omni-channel-identity-enrichment-hook"; private final ModuleConfig config; @@ -44,14 +47,16 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( @Override public Future> call(AuctionRequestPayload auctionRequestPayload, AuctionInvocationContext invocationContext) { - return requestEnrichment(auctionRequestPayload) + Future> update = requestEnrichment(auctionRequestPayload) .map(resolutionResult -> InvocationResultImpl.builder() - .status(InvocationStatus.success) - .action(InvocationAction.update) - .payloadUpdate(requestPayload -> updatedPayload(requestPayload, resolutionResult)) - .build() + .status(InvocationStatus.success) + .action(InvocationAction.update) + .payloadUpdate(requestPayload -> updatedPayload(requestPayload, resolutionResult)) + .build() ); + + return update.onFailure(throwable -> logger.error("Failed enrichment:", throwable)); } @Override From a863d0a198131b6fb900cdfedc428d9632899789 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 7 May 2025 10:06:23 +0200 Subject: [PATCH 09/34] Add docs --- extra/modules/live-intent-omni-channel-identity/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/README.md b/extra/modules/live-intent-omni-channel-identity/README.md index 526da24fe9a..29ff4e55c78 100644 --- a/extra/modules/live-intent-omni-channel-identity/README.md +++ b/extra/modules/live-intent-omni-channel-identity/README.md @@ -1,10 +1,12 @@ # Overview -This module enriches bid requests with user IDs that it adds to the user EIDs. +This module enriches bid requests with user IDs that it adds to the user EIDs. -The user IDs to be enriched are configured on LiveIntent's side. The set of user IDs accessible by a partner are determined by the auth token provided in the settings. +The user IDs to be enriched are configured on LiveIntent's side. The set of user IDs accessible by a partner are +determined by the auth token provided in the settings. ## Configuration + To start using the LiveIntent Omni Channel Identity module you have to enable it and add configuration: ```yaml From 62a4508811b3fb6937446672bb8090946baf8153 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 7 May 2025 10:06:43 +0200 Subject: [PATCH 10/34] Format --- extra/modules/live-intent-omni-channel-identity/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extra/modules/live-intent-omni-channel-identity/pom.xml b/extra/modules/live-intent-omni-channel-identity/pom.xml index d1bf2a08aff..03cf291d0da 100644 --- a/extra/modules/live-intent-omni-channel-identity/pom.xml +++ b/extra/modules/live-intent-omni-channel-identity/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.prebid.server.hooks.modules From e45ccbc1009dda931d0ad06c82bd5d89c9cac8ac Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 7 May 2025 10:13:52 +0200 Subject: [PATCH 11/34] Impro docs --- extra/modules/live-intent-omni-channel-identity/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/README.md b/extra/modules/live-intent-omni-channel-identity/README.md index 29ff4e55c78..3e375864088 100644 --- a/extra/modules/live-intent-omni-channel-identity/README.md +++ b/extra/modules/live-intent-omni-channel-identity/README.md @@ -1,9 +1,8 @@ # Overview -This module enriches bid requests with user IDs that it adds to the user EIDs. +This module enriches bid requests with user EIDs. -The user IDs to be enriched are configured on LiveIntent's side. The set of user IDs accessible by a partner are -determined by the auth token provided in the settings. +The user EIDs to be enriched are configured per partner as part of the LiveIntent HIRO onboarding process. ## Configuration @@ -41,5 +40,5 @@ hooks: identity-resolution-endpoint: "https://liveintent.com/idx" auth-token: "secret-token" ``` - +The partner-specific `auth-token` is provided by LiveIntent as part of the onboarding. From 3dbb46ae7ce97864a55086c190cf38f3b3613287 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 7 May 2025 12:39:28 +0200 Subject: [PATCH 12/34] Add IdResResponse decode test --- .../model/config/IdResResponseTest.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java new file mode 100644 index 00000000000..d4e434f2942 --- /dev/null +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java @@ -0,0 +1,29 @@ +package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.IdResResponse; +import org.prebid.server.json.JacksonMapper; + +import static org.assertj.core.api.Assertions.assertThat; + +public class IdResResponseTest { + private JacksonMapper jacksonMapper; + + @BeforeEach + public void setUp() { + ObjectMapper mapper = new ObjectMapper(); + jacksonMapper = new JacksonMapper(mapper); + } + + @Test + public void shouldDecodeFromString() { + IdResResponse result = jacksonMapper.decodeValue("{\"eids\": [ { \"source\": \"liveintent.com\", \"uids\": [ { \"atype\": 3, \"id\" : \"some_id\" } ] } ] }", IdResResponse.class); + assertThat(result.getEids()).hasSize(1); + assertThat(result.getEids().getFirst().getSource()).isEqualTo("liveintent.com"); + assertThat(result.getEids().getFirst().getUids()).hasSize(1); + assertThat(result.getEids().getFirst().getUids().getFirst().getAtype()).isEqualTo(3); + assertThat(result.getEids().getFirst().getUids().getFirst().getId()).isEqualTo("some_id"); + } +} From 69fc41353876955d800bbc1827e501a099e9d028 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 7 May 2025 13:00:42 +0200 Subject: [PATCH 13/34] Improve code style --- ...ntentOmniChannelIdentityConfiguration.java | 3 +- ...elIdentityProcessedAuctionRequestHook.java | 18 ++++---- .../model/config/IdResResponseTest.java | 2 + .../model/config/ModuleConfigTest.java | 4 ++ ...entityProcessedAuctionRequestHookTest.java | 46 +++++++++++-------- 5 files changed, 44 insertions(+), 29 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index 0bc46332f3c..ecceb0a4176 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -27,8 +27,7 @@ ModuleConfig moduleConfig() { @Bean Module liveIntentOmniChannelIdentityModule(ModuleConfig config, JacksonMapper mapper, HttpClient httpClient) { final Set> hooks = Set.of( - new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(config, mapper, httpClient) - ); + new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(config, mapper, httpClient)); return new LiveIntentOmniChannelIdentityModule(hooks); } } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index de0720c59c8..3b93f788bef 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -23,6 +23,7 @@ import org.prebid.server.vertx.httpclient.model.HttpClientResponse; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -40,6 +41,7 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( ModuleConfig config, JacksonMapper mapper, HttpClient httpClient) { + this.config = Objects.requireNonNull(config); this.mapper = Objects.requireNonNull(mapper); this.httpClient = Objects.requireNonNull(httpClient); @@ -47,7 +49,7 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( @Override public Future> call(AuctionRequestPayload auctionRequestPayload, AuctionInvocationContext invocationContext) { - Future> update = requestEnrichment(auctionRequestPayload) + final Future> update = requestEnrichment(auctionRequestPayload) .map(resolutionResult -> InvocationResultImpl.builder() .status(InvocationStatus.success) @@ -65,21 +67,21 @@ public String code() { } private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayload, IdResResponse idResResponse) { - BidRequest bidRequest = Optional.ofNullable(requestPayload.bidRequest()).orElse(BidRequest.builder().build()); - User user = Optional.ofNullable(bidRequest.getUser()).orElse(User.builder().build()); + final BidRequest bidRequest = Optional.ofNullable(requestPayload.bidRequest()).orElse(BidRequest.builder().build()); + final User user = Optional.ofNullable(bidRequest.getUser()).orElse(User.builder().build()); - List allEids = new ArrayList<>(); - allEids.addAll(Optional.ofNullable(user.getEids()).orElse(List.of())); + final List allEids = new ArrayList<>(); + allEids.addAll(Optional.ofNullable(user.getEids()).orElse(Collections.emptyList())); allEids.addAll(idResResponse.getEids()); - User updatedUser = user.toBuilder().eids(allEids).build(); - BidRequest updatedBidRequest = requestPayload.bidRequest().toBuilder().user(updatedUser).build(); + final User updatedUser = user.toBuilder().eids(allEids).build(); + final BidRequest updatedBidRequest = requestPayload.bidRequest().toBuilder().user(updatedUser).build(); return AuctionRequestPayloadImpl.of(updatedBidRequest); } private Future requestEnrichment(AuctionRequestPayload auctionRequestPayload) { - String bidRequestJson = mapper.encodeToString(auctionRequestPayload.bidRequest()); + final String bidRequestJson = mapper.encodeToString(auctionRequestPayload.bidRequest()); return httpClient.post( config.getIdentityResolutionEndpoint(), headers(), diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java index d4e434f2942..97fbb40e8d8 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java @@ -19,7 +19,9 @@ public void setUp() { @Test public void shouldDecodeFromString() { + // given IdResResponse result = jacksonMapper.decodeValue("{\"eids\": [ { \"source\": \"liveintent.com\", \"uids\": [ { \"atype\": 3, \"id\" : \"some_id\" } ] } ] }", IdResResponse.class); + // when and then assertThat(result.getEids()).hasSize(1); assertThat(result.getEids().getFirst().getSource()).isEqualTo("liveintent.com"); assertThat(result.getEids().getFirst().getUids()).hasSize(1); diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java index 1fa4860b023..0ca4f894689 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java @@ -14,15 +14,19 @@ public void shouldReturnRequestTimeoutMs() { @Test public void shouldReturnIdentityResolutionEndpoint() { + // given ModuleConfig moduleConfig = new ModuleConfig(); moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); + // when and then assertThat(moduleConfig.getIdentityResolutionEndpoint()).isEqualTo("https://test.com/idres"); } @Test public void shouldReturnAuthToken() { + // given ModuleConfig moduleConfig = new ModuleConfig(); moduleConfig.setAuthToken("secret_token"); + // when and then assertThat(moduleConfig.getAuthToken()).isEqualTo("secret_token"); } } diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index 155746a1e54..bef35918db7 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -7,6 +7,7 @@ import com.iab.openrtb.request.User; import io.vertx.core.Future; import io.vertx.core.MultiMap; +import org.assertj.core.api.ListAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -27,6 +28,7 @@ import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; +import java.util.Collections; import java.util.List; import java.util.function.Consumer; @@ -64,20 +66,22 @@ public void setUp() { @Test public void shouldAddResolvedEids() { - Uid providedUid = Uid.builder().id("id1").atype(2).build(); - Eid providedEid = Eid.builder().source("some.source.com").uids(List.of(providedUid)).build(); + // given + final Uid providedUid = Uid.builder().id("id1").atype(2).build(); + final Eid providedEid = Eid.builder().source("some.source.com").uids(Collections.singletonList(providedUid)).build(); - Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); - Eid enrichedEid = Eid.builder().source("liveintent.com").uids(List.of(enrichedUid)).build(); + final Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); + final Eid enrichedEid = Eid.builder().source("liveintent.com").uids(Collections.singletonList(enrichedUid)).build(); - User user = User.builder().eids(List.of(providedEid)).build(); - BidRequest bidRequest = BidRequest.builder().id("request").user(user).build(); + final User user = User.builder().eids(Collections.singletonList(providedEid)).build(); + final BidRequest bidRequest = BidRequest.builder().id("request").user(user).build(); - AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); + final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); - HttpClientResponse mockResponse = mock(HttpClientResponse.class); + final HttpClientResponse mockResponse = mock(HttpClientResponse.class); when(mockResponse.getBody()).thenReturn("{\"eids\": [ { \"source\": \"" + enrichedEid.getSource() + "\", \"uids\": [ { \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" } ] } ] }"); + // when when( httpClient.post( eq(moduleConfig.getIdentityResolutionEndpoint()), @@ -92,27 +96,30 @@ public boolean matches(MultiMap entries) { ) ).thenReturn(Future.succeededFuture(mockResponse)); - Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); - InvocationResult result = future.result(); + final Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); + final InvocationResult result = future.result(); + // then assertThat(future).isNotNull(); assertThat(future.succeeded()).isTrue(); assertThat(result).isNotNull(); assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); - assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(List.of(providedEid, enrichedEid)); + assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(Collections.singletonList(providedEid).add(enrichedEid)); } @Test public void shouldCreateUserWhenNotPresent() { - Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); - Eid enrichedEid = Eid.builder().source("liveintent.com").uids(List.of(enrichedUid)).build(); + // given + final Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); + final Eid enrichedEid = Eid.builder().source("liveintent.com").uids(Collections.singletonList(enrichedUid)).build(); - BidRequest bidRequest = BidRequest.builder().id("request").build(); + final BidRequest bidRequest = BidRequest.builder().id("request").build(); - AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); + final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); - HttpClientResponse mockResponse = mock(HttpClientResponse.class); + // when + final HttpClientResponse mockResponse = mock(HttpClientResponse.class); when(mockResponse.getBody()).thenReturn("{\"eids\": [{ \"source\": \"" + enrichedEid.getSource() + "\", \"uids\": [{ \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" }]}]}"); when( @@ -129,14 +136,15 @@ public boolean matches(MultiMap entries) { ) ).thenReturn(Future.succeededFuture(mockResponse)); - Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); - InvocationResult result = future.result(); + final Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); + final InvocationResult result = future.result(); + // then assertThat(future).isNotNull(); assertThat(future.succeeded()).isTrue(); assertThat(result).isNotNull(); assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); - assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(List.of(enrichedEid)); + assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(Collections.singletonList(enrichedEid)); } } From c1ad22fc2ef901a5897ceef50fec44fcd1d3173e Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 7 May 2025 13:05:08 +0200 Subject: [PATCH 14/34] Fix Collections API usage --- ...ntentOmniChannelIdentityProcessedAuctionRequestHookTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index bef35918db7..bdf0f513cf1 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -105,7 +105,7 @@ public boolean matches(MultiMap entries) { assertThat(result).isNotNull(); assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); - assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(Collections.singletonList(providedEid).add(enrichedEid)); + assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(List.of(providedEid, enrichedEid)); } @Test From 26288b7d43300bb96d2bc814b9c86505ea0addb4 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 14 May 2025 16:05:27 +0200 Subject: [PATCH 15/34] Clean up/format --- .../README.md | 3 +- ...ntentOmniChannelIdentityConfiguration.java | 5 ++- .../channel/identity/model/IdResResponse.java | 1 + .../identity/model/config/ModuleConfig.java | 1 + ...elIdentityProcessedAuctionRequestHook.java | 11 +++-- .../model/config/IdResResponseTest.java | 8 +++- .../model/config/ModuleConfigTest.java | 7 +-- ...entityProcessedAuctionRequestHookTest.java | 43 ++++++++++++------- 8 files changed, 53 insertions(+), 26 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/README.md b/extra/modules/live-intent-omni-channel-identity/README.md index 3e375864088..1165bdcb850 100644 --- a/extra/modules/live-intent-omni-channel-identity/README.md +++ b/extra/modules/live-intent-omni-channel-identity/README.md @@ -2,7 +2,7 @@ This module enriches bid requests with user EIDs. -The user EIDs to be enriched are configured per partner as part of the LiveIntent HIRO onboarding process. +The user EIDs to be enriched are configured per partner as part of the LiveIntent HIRO onboarding process. ## Configuration @@ -40,5 +40,6 @@ hooks: identity-resolution-endpoint: "https://liveintent.com/idx" auth-token: "secret-token" ``` + The partner-specific `auth-token` is provided by LiveIntent as part of the onboarding. diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index ecceb0a4176..c140eac0cb3 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -16,8 +16,11 @@ import java.util.Set; @Configuration -@ConditionalOnProperty(prefix = "hooks." + LiveIntentOmniChannelIdentityModule.CODE, name = "enabled", havingValue = "true") +@ConditionalOnProperty( + prefix = "hooks." + LiveIntentOmniChannelIdentityModule.CODE, name = "enabled", havingValue = "true" +) public class LiveIntentOmniChannelIdentityConfiguration { + @Bean @ConfigurationProperties(prefix = "hooks.modules." + LiveIntentOmniChannelIdentityModule.CODE) ModuleConfig moduleConfig() { diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java index 0e72f5763ce..aba48041b37 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java @@ -12,6 +12,7 @@ @Data @Jacksonized public class IdResResponse { + @JsonProperty("eids") List eids; } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java index cf35c8e9211..e7ed2893856 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java @@ -4,6 +4,7 @@ @Data public final class ModuleConfig { + long requestTimeoutMs; String identityResolutionEndpoint; String authToken; diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 3b93f788bef..95db7b2bd55 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -30,7 +30,8 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { - private static final Logger logger = LoggerFactory.getLogger(LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.class); + private static final Logger logger = + LoggerFactory.getLogger(LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.class); private static final String CODE = "liveintent-omni-channel-identity-enrichment-hook"; private final ModuleConfig config; @@ -48,7 +49,10 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( } @Override - public Future> call(AuctionRequestPayload auctionRequestPayload, AuctionInvocationContext invocationContext) { + public Future> call( + AuctionRequestPayload auctionRequestPayload, + AuctionInvocationContext invocationContext + ) { final Future> update = requestEnrichment(auctionRequestPayload) .map(resolutionResult -> InvocationResultImpl.builder() @@ -67,7 +71,8 @@ public String code() { } private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayload, IdResResponse idResResponse) { - final BidRequest bidRequest = Optional.ofNullable(requestPayload.bidRequest()).orElse(BidRequest.builder().build()); + final BidRequest bidRequest = Optional.ofNullable( + requestPayload.bidRequest()).orElse(BidRequest.builder().build()); final User user = Optional.ofNullable(bidRequest.getUser()).orElse(User.builder().build()); final List allEids = new ArrayList<>(); diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java index 97fbb40e8d8..d6fb7da9b01 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java @@ -9,18 +9,22 @@ import static org.assertj.core.api.Assertions.assertThat; public class IdResResponseTest { + private JacksonMapper jacksonMapper; @BeforeEach public void setUp() { - ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = new ObjectMapper(); jacksonMapper = new JacksonMapper(mapper); } @Test public void shouldDecodeFromString() { // given - IdResResponse result = jacksonMapper.decodeValue("{\"eids\": [ { \"source\": \"liveintent.com\", \"uids\": [ { \"atype\": 3, \"id\" : \"some_id\" } ] } ] }", IdResResponse.class); + final IdResResponse result = jacksonMapper.decodeValue( + "{\"eids\": [ { \"source\": \"liveintent.com\", " + + "\"uids\": [ { \"atype\": 3, \"id\" : \"some_id\" } ] } ] }", + IdResResponse.class); // when and then assertThat(result.getEids()).hasSize(1); assertThat(result.getEids().getFirst().getSource()).isEqualTo("liveintent.com"); diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java index 0ca4f894689..e1a90c411bd 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java @@ -5,9 +5,10 @@ import static org.assertj.core.api.Assertions.assertThat; public class ModuleConfigTest { + @Test public void shouldReturnRequestTimeoutMs() { - ModuleConfig moduleConfig = new ModuleConfig(); + final ModuleConfig moduleConfig = new ModuleConfig(); moduleConfig.setRequestTimeoutMs(5); assertThat(moduleConfig.getRequestTimeoutMs()).isEqualTo(5); } @@ -15,7 +16,7 @@ public void shouldReturnRequestTimeoutMs() { @Test public void shouldReturnIdentityResolutionEndpoint() { // given - ModuleConfig moduleConfig = new ModuleConfig(); + final ModuleConfig moduleConfig = new ModuleConfig(); moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); // when and then assertThat(moduleConfig.getIdentityResolutionEndpoint()).isEqualTo("https://test.com/idres"); @@ -24,7 +25,7 @@ public void shouldReturnIdentityResolutionEndpoint() { @Test public void shouldReturnAuthToken() { // given - ModuleConfig moduleConfig = new ModuleConfig(); + final ModuleConfig moduleConfig = new ModuleConfig(); moduleConfig.setAuthToken("secret_token"); // when and then assertThat(moduleConfig.getAuthToken()).isEqualTo("secret_token"); diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index bdf0f513cf1..3c6c2c79b82 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -7,7 +7,6 @@ import com.iab.openrtb.request.User; import io.vertx.core.Future; import io.vertx.core.MultiMap; -import org.assertj.core.api.ListAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -24,20 +23,15 @@ import org.prebid.server.hooks.v1.auction.AuctionInvocationContext; import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; import org.prebid.server.json.JacksonMapper; -import org.prebid.server.util.HttpUtil; import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; import java.util.Collections; import java.util.List; -import java.util.function.Consumer; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.assertArg; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -50,7 +44,7 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest { @BeforeEach public void setUp() { - ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = new ObjectMapper(); jacksonMapper = new JacksonMapper(mapper); moduleConfig = new ModuleConfig(); @@ -68,18 +62,26 @@ public void setUp() { public void shouldAddResolvedEids() { // given final Uid providedUid = Uid.builder().id("id1").atype(2).build(); - final Eid providedEid = Eid.builder().source("some.source.com").uids(Collections.singletonList(providedUid)).build(); + final Eid providedEid = Eid.builder().source("some.source.com") + .uids(Collections.singletonList(providedUid)).build(); final Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); - final Eid enrichedEid = Eid.builder().source("liveintent.com").uids(Collections.singletonList(enrichedUid)).build(); + final Eid enrichedEid = Eid.builder().source("liveintent.com") + .uids(Collections.singletonList(enrichedUid)).build(); final User user = User.builder().eids(Collections.singletonList(providedEid)).build(); final BidRequest bidRequest = BidRequest.builder().id("request").user(user).build(); - final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); + final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( + null, null, false, null, null); final HttpClientResponse mockResponse = mock(HttpClientResponse.class); - when(mockResponse.getBody()).thenReturn("{\"eids\": [ { \"source\": \"" + enrichedEid.getSource() + "\", \"uids\": [ { \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" } ] } ] }"); + when(mockResponse.getBody()) + .thenReturn("{\"eids\": [ { \"source\": \"" + enrichedEid.getSource() + + "\", \"uids\": [ { \"atype\": " + + enrichedUid.getAtype() + + ", \"id\" : \"" + + enrichedUid.getId() + "\" } ] } ] }"); // when when( @@ -96,7 +98,8 @@ public boolean matches(MultiMap entries) { ) ).thenReturn(Future.succeededFuture(mockResponse)); - final Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); + final Future> future = + target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); final InvocationResult result = future.result(); // then @@ -105,22 +108,30 @@ public boolean matches(MultiMap entries) { assertThat(result).isNotNull(); assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); - assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(List.of(providedEid, enrichedEid)); + assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)) + .bidRequest().getUser().getEids()).isEqualTo(List.of(providedEid, enrichedEid)); } @Test public void shouldCreateUserWhenNotPresent() { // given final Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); - final Eid enrichedEid = Eid.builder().source("liveintent.com").uids(Collections.singletonList(enrichedUid)).build(); + final Eid enrichedEid = Eid.builder().source("liveintent.com") + .uids(Collections.singletonList(enrichedUid)).build(); final BidRequest bidRequest = BidRequest.builder().id("request").build(); - final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of(null, null, false, null, null); + final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( + null, null, false, null, null); // when final HttpClientResponse mockResponse = mock(HttpClientResponse.class); - when(mockResponse.getBody()).thenReturn("{\"eids\": [{ \"source\": \"" + enrichedEid.getSource() + "\", \"uids\": [{ \"atype\": " + enrichedUid.getAtype() + ", \"id\" : \"" + enrichedUid.getId() + "\" }]}]}"); + when(mockResponse.getBody()) + .thenReturn("{\"eids\": [{ \"source\": \"" + + enrichedEid.getSource() + + "\", \"uids\": [{ \"atype\": " + + enrichedUid.getAtype() + ", \"id\" : \"" + + enrichedUid.getId() + "\" }]}]}"); when( httpClient.post( From 1f1a7cfc1aae98ad2422cb73b95552005f037194 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Mon, 19 May 2025 11:39:40 +0200 Subject: [PATCH 16/34] Format --- extra/modules/live-intent-omni-channel-identity/pom.xml | 2 +- .../LiveIntentOmniChannelIdentityConfiguration.java | 2 +- ...niChannelIdentityProcessedAuctionRequestHookTest.java | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/pom.xml b/extra/modules/live-intent-omni-channel-identity/pom.xml index 03cf291d0da..e38a2199e23 100644 --- a/extra/modules/live-intent-omni-channel-identity/pom.xml +++ b/extra/modules/live-intent-omni-channel-identity/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 3.25.0-SNAPSHOT + 3.26.0-SNAPSHOT live-intent-omni-channel-identity diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index c140eac0cb3..88ba0f7292e 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -17,7 +17,7 @@ @Configuration @ConditionalOnProperty( - prefix = "hooks." + LiveIntentOmniChannelIdentityModule.CODE, name = "enabled", havingValue = "true" + prefix = "hooks." + LiveIntentOmniChannelIdentityModule.CODE, name = "enabled", havingValue = "true" ) public class LiveIntentOmniChannelIdentityConfiguration { diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index 3c6c2c79b82..f213fd13ea3 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -147,7 +147,8 @@ public boolean matches(MultiMap entries) { ) ).thenReturn(Future.succeededFuture(mockResponse)); - final Future> future = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); + final Future> future + = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); final InvocationResult result = future.result(); // then @@ -156,6 +157,10 @@ public boolean matches(MultiMap entries) { assertThat(result).isNotNull(); assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); - assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)).bidRequest().getUser().getEids()).isEqualTo(Collections.singletonList(enrichedEid)); + assertThat(result.payloadUpdate() + .apply(AuctionRequestPayloadImpl.of(bidRequest)) + .bidRequest() + .getUser() + .getEids()).isEqualTo(Collections.singletonList(enrichedEid)); } } From c9659addd035a8686d4ed85fbd12643fcd27c23d Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Mon, 19 May 2025 13:02:22 +0200 Subject: [PATCH 17/34] Add treatment rate --- .../README.md | 7 +-- .../identity/model/config/ModuleConfig.java | 1 + ...elIdentityProcessedAuctionRequestHook.java | 40 +++++++++++---- ...entityProcessedAuctionRequestHookTest.java | 51 ++++++++++++++++--- 4 files changed, 80 insertions(+), 19 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/README.md b/extra/modules/live-intent-omni-channel-identity/README.md index 1165bdcb850..be5ad801ec1 100644 --- a/extra/modules/live-intent-omni-channel-identity/README.md +++ b/extra/modules/live-intent-omni-channel-identity/README.md @@ -2,7 +2,9 @@ This module enriches bid requests with user EIDs. -The user EIDs to be enriched are configured per partner as part of the LiveIntent HIRO onboarding process. +The user EIDs to be enriched are configured per partner as part of the LiveIntent HIRO onboarding process. As part of this onboarding process, partners will also be provided with the `identity-resolution-endpoint` URL as well as with the `auth-token`. + +`treatment-rate` is a value between 0.0 and 1.0 (including 0.0 and 1.0) and defines the percentage of requests for which identity enrichment should be performed. This value can be freely picked. We recommend a value between 0.9 and 0.95 ## Configuration @@ -39,7 +41,6 @@ hooks: request-timeout-ms: 2000 identity-resolution-endpoint: "https://liveintent.com/idx" auth-token: "secret-token" + treatment-rate: 0.9 ``` -The partner-specific `auth-token` is provided by LiveIntent as part of the onboarding. - diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java index e7ed2893856..f17bc3c549d 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java @@ -8,4 +8,5 @@ public final class ModuleConfig { long requestTimeoutMs; String identityResolutionEndpoint; String authToken; + float treatmentRate; } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 95db7b2bd55..ac5024a3b9b 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Random; public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { @@ -37,15 +38,26 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements private final ModuleConfig config; private final JacksonMapper mapper; private final HttpClient httpClient; + private final Random random; public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( ModuleConfig config, JacksonMapper mapper, HttpClient httpClient) { + this(config, mapper, httpClient, new Random()); + } + + public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( + ModuleConfig config, + JacksonMapper mapper, + HttpClient httpClient, + Random random) { + this.config = Objects.requireNonNull(config); this.mapper = Objects.requireNonNull(mapper); this.httpClient = Objects.requireNonNull(httpClient); + this.random = random; } @Override @@ -53,16 +65,24 @@ public Future> call( AuctionRequestPayload auctionRequestPayload, AuctionInvocationContext invocationContext ) { - final Future> update = requestEnrichment(auctionRequestPayload) - .map(resolutionResult -> - InvocationResultImpl.builder() - .status(InvocationStatus.success) - .action(InvocationAction.update) - .payloadUpdate(requestPayload -> updatedPayload(requestPayload, resolutionResult)) - .build() - ); - - return update.onFailure(throwable -> logger.error("Failed enrichment:", throwable)); + if (random.nextFloat() < config.getTreatmentRate()) { + final Future> update = requestEnrichment(auctionRequestPayload) + .map(resolutionResult -> + InvocationResultImpl.builder() + .status(InvocationStatus.success) + .action(InvocationAction.update) + .payloadUpdate(requestPayload -> updatedPayload(requestPayload, resolutionResult)) + .build() + ); + + return update.onFailure(throwable -> logger.error("Failed enrichment:", throwable)); + } else { + return Future.succeededFuture( + InvocationResultImpl.builder() + .status(InvocationStatus.success) + .action(InvocationAction.no_action) + .build()); + } } @Override diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index f213fd13ea3..488df3ec770 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -28,6 +28,7 @@ import java.util.Collections; import java.util.List; +import java.util.Random; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.argThat; @@ -42,6 +43,11 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest { private LiveIntentOmniChannelIdentityProcessedAuctionRequestHook target; private JacksonMapper jacksonMapper; + @Mock + private HttpClient httpClient; + @Mock + private Random random; + @BeforeEach public void setUp() { final ObjectMapper mapper = new ObjectMapper(); @@ -51,13 +57,12 @@ public void setUp() { moduleConfig.setRequestTimeoutMs(5); moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); moduleConfig.setAuthToken("secret_auth_token"); + moduleConfig.setTreatmentRate(0.9f); - target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(moduleConfig, jacksonMapper, httpClient); + target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( + moduleConfig, jacksonMapper, httpClient, random); } - @Mock - private HttpClient httpClient; - @Test public void shouldAddResolvedEids() { // given @@ -76,6 +81,9 @@ public void shouldAddResolvedEids() { null, null, false, null, null); final HttpClientResponse mockResponse = mock(HttpClientResponse.class); + // when + when(random.nextFloat()).thenReturn(0.89f); + when(mockResponse.getBody()) .thenReturn("{\"eids\": [ { \"source\": \"" + enrichedEid.getSource() + "\", \"uids\": [ { \"atype\": " @@ -83,7 +91,6 @@ public void shouldAddResolvedEids() { + ", \"id\" : \"" + enrichedUid.getId() + "\" } ] } ] }"); - // when when( httpClient.post( eq(moduleConfig.getIdentityResolutionEndpoint()), @@ -112,6 +119,35 @@ public boolean matches(MultiMap entries) { .bidRequest().getUser().getEids()).isEqualTo(List.of(providedEid, enrichedEid)); } + @Test + public void shouldNotAttemptToResolveEids() { + // given + final Uid providedUid = Uid.builder().id("id1").atype(2).build(); + final Eid providedEid = Eid.builder().source("some.source.com") + .uids(Collections.singletonList(providedUid)).build(); + + final User user = User.builder().eids(Collections.singletonList(providedEid)).build(); + final BidRequest bidRequest = BidRequest.builder().id("request").user(user).build(); + + final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( + null, null, false, null, null); + + // when + when(random.nextFloat()).thenReturn(0.91f); + + final Future> future = + target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); + final InvocationResult result = future.result(); + + // then + 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.payloadUpdate()).isNull(); + } + @Test public void shouldCreateUserWhenNotPresent() { // given @@ -124,8 +160,11 @@ public void shouldCreateUserWhenNotPresent() { final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( null, null, false, null, null); - // when final HttpClientResponse mockResponse = mock(HttpClientResponse.class); + + // when + when(random.nextFloat()).thenReturn(0.89f); + when(mockResponse.getBody()) .thenReturn("{\"eids\": [{ \"source\": \"" + enrichedEid.getSource() From 3ed7ee8d98514b029711e342629f7c247a7cf8c1 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:18:41 +0200 Subject: [PATCH 18/34] Remove superflous JsonProperty annotation --- .../liveintent/omni/channel/identity/model/IdResResponse.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java index aba48041b37..3f8432e36c5 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java @@ -1,6 +1,5 @@ package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model; -import com.fasterxml.jackson.annotation.JsonProperty; import com.iab.openrtb.request.Eid; import lombok.Builder; import lombok.Data; @@ -13,6 +12,5 @@ @Jacksonized public class IdResResponse { - @JsonProperty("eids") List eids; } From bedb9690e7153306f5e781573b3d2848852dc38e Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:19:45 +0200 Subject: [PATCH 19/34] Separate field by line --- .../omni/channel/identity/model/config/ModuleConfig.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java index f17bc3c549d..a7fc92b1feb 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java @@ -6,7 +6,10 @@ public final class ModuleConfig { long requestTimeoutMs; + String identityResolutionEndpoint; + String authToken; + float treatmentRate; } From d94e06f044228661bfa161078bbc4d6e434eccd1 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:36:29 +0200 Subject: [PATCH 20/34] Use RandomGenerator + ThreadLocalRandom instead of Random --- ...LiveIntentOmniChannelIdentityConfiguration.java | 4 +++- ...ChannelIdentityProcessedAuctionRequestHook.java | 14 +++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index 88ba0f7292e..efc98d4d105 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -14,6 +14,7 @@ import org.springframework.context.annotation.Configuration; import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; @Configuration @ConditionalOnProperty( @@ -30,7 +31,8 @@ ModuleConfig moduleConfig() { @Bean Module liveIntentOmniChannelIdentityModule(ModuleConfig config, JacksonMapper mapper, HttpClient httpClient) { final Set> hooks = Set.of( - new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(config, mapper, httpClient)); + new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( + config, mapper, httpClient, () -> ThreadLocalRandom.current().nextLong())); return new LiveIntentOmniChannelIdentityModule(hooks); } } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index ac5024a3b9b..6ab5db8a13f 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -27,7 +27,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.Random; +import java.util.random.RandomGenerator; public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { @@ -38,21 +38,13 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements private final ModuleConfig config; private final JacksonMapper mapper; private final HttpClient httpClient; - private final Random random; - - public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( - ModuleConfig config, - JacksonMapper mapper, - HttpClient httpClient) { - - this(config, mapper, httpClient, new Random()); - } + private final RandomGenerator random; public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( ModuleConfig config, JacksonMapper mapper, HttpClient httpClient, - Random random) { + RandomGenerator random) { this.config = Objects.requireNonNull(config); this.mapper = Objects.requireNonNull(mapper); From 61ceeed89ff2ce30d1103428185a0d4461b825ce Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:47:31 +0200 Subject: [PATCH 21/34] Apply code style --- ...veIntentOmniChannelIdentityProcessedAuctionRequestHook.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 6ab5db8a13f..9494ee19f3f 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -64,8 +64,7 @@ public Future> call( .status(InvocationStatus.success) .action(InvocationAction.update) .payloadUpdate(requestPayload -> updatedPayload(requestPayload, resolutionResult)) - .build() - ); + .build()); return update.onFailure(throwable -> logger.error("Failed enrichment:", throwable)); } else { From fa66d1846282ae717d4dd0c840b238c8ca35b63d Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:49:40 +0200 Subject: [PATCH 22/34] Apply style guide: method order --- ...elIdentityProcessedAuctionRequestHook.java | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 9494ee19f3f..d1c6cba6d2f 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -76,9 +76,23 @@ public Future> call( } } - @Override - public String code() { - return CODE; + private Future requestEnrichment(AuctionRequestPayload auctionRequestPayload) { + final String bidRequestJson = mapper.encodeToString(auctionRequestPayload.bidRequest()); + return httpClient.post( + config.getIdentityResolutionEndpoint(), + headers(), + bidRequestJson, + config.getRequestTimeoutMs()) + .map(this::processResponse); + } + + private MultiMap headers() { + return MultiMap.caseInsensitiveMultiMap() + .add(HttpUtil.AUTHORIZATION_HEADER, "Bearer " + config.getAuthToken()); + } + + private IdResResponse processResponse(HttpClientResponse response) { + return mapper.decodeValue(response.getBody(), IdResResponse.class); } private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayload, IdResResponse idResResponse) { @@ -96,22 +110,8 @@ private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayloa return AuctionRequestPayloadImpl.of(updatedBidRequest); } - private Future requestEnrichment(AuctionRequestPayload auctionRequestPayload) { - final String bidRequestJson = mapper.encodeToString(auctionRequestPayload.bidRequest()); - return httpClient.post( - config.getIdentityResolutionEndpoint(), - headers(), - bidRequestJson, - config.getRequestTimeoutMs()) - .map(this::processResponse); - } - - private IdResResponse processResponse(HttpClientResponse response) { - return mapper.decodeValue(response.getBody(), IdResResponse.class); - } - - private MultiMap headers() { - return MultiMap.caseInsensitiveMultiMap() - .add(HttpUtil.AUTHORIZATION_HEADER, "Bearer " + config.getAuthToken()); + @Override + public String code() { + return CODE; } } From 09450d257e08f242000080a105442f9e288b6bad Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:53:13 +0200 Subject: [PATCH 23/34] Add empty lines to separate test stages --- .../omni/channel/identity/model/config/IdResResponseTest.java | 1 + .../omni/channel/identity/model/config/ModuleConfigTest.java | 2 ++ ...ntentOmniChannelIdentityProcessedAuctionRequestHookTest.java | 1 + 3 files changed, 4 insertions(+) diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java index d6fb7da9b01..d53854e7eea 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java @@ -25,6 +25,7 @@ public void shouldDecodeFromString() { "{\"eids\": [ { \"source\": \"liveintent.com\", " + "\"uids\": [ { \"atype\": 3, \"id\" : \"some_id\" } ] } ] }", IdResResponse.class); + // when and then assertThat(result.getEids()).hasSize(1); assertThat(result.getEids().getFirst().getSource()).isEqualTo("liveintent.com"); diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java index e1a90c411bd..39cfd34298e 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java @@ -18,6 +18,7 @@ public void shouldReturnIdentityResolutionEndpoint() { // given final ModuleConfig moduleConfig = new ModuleConfig(); moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); + // when and then assertThat(moduleConfig.getIdentityResolutionEndpoint()).isEqualTo("https://test.com/idres"); } @@ -27,6 +28,7 @@ public void shouldReturnAuthToken() { // given final ModuleConfig moduleConfig = new ModuleConfig(); moduleConfig.setAuthToken("secret_token"); + // when and then assertThat(moduleConfig.getAuthToken()).isEqualTo("secret_token"); } diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index 488df3ec770..f454fd2ce99 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -81,6 +81,7 @@ public void shouldAddResolvedEids() { null, null, false, null, null); final HttpClientResponse mockResponse = mock(HttpClientResponse.class); + // when when(random.nextFloat()).thenReturn(0.89f); From b588f6a641da1d9fb8b7907ed5846ad5e2592e6e Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 11 Jun 2025 14:17:09 +0200 Subject: [PATCH 24/34] Use NoArgsConstructor instead of Jacksonized --- .../omni/channel/identity/model/IdResResponse.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java index 3f8432e36c5..c94df691c2f 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java @@ -1,15 +1,13 @@ package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model; import com.iab.openrtb.request.Eid; -import lombok.Builder; import lombok.Data; -import lombok.extern.jackson.Jacksonized; +import lombok.NoArgsConstructor; import java.util.List; -@Builder @Data -@Jacksonized +@NoArgsConstructor public class IdResResponse { List eids; From f597339101608ddd0effaa719e0cac6d50e5565e Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 11 Jun 2025 18:14:55 +0200 Subject: [PATCH 25/34] Bump dependency version --- extra/modules/live-intent-omni-channel-identity/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/modules/live-intent-omni-channel-identity/pom.xml b/extra/modules/live-intent-omni-channel-identity/pom.xml index e38a2199e23..95863109ecd 100644 --- a/extra/modules/live-intent-omni-channel-identity/pom.xml +++ b/extra/modules/live-intent-omni-channel-identity/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 3.26.0-SNAPSHOT + 3.27.0-SNAPSHOT live-intent-omni-channel-identity From 5f15bf19db3ce39959423f9c45b3d473d5cda670 Mon Sep 17 00:00:00 2001 From: ilya Date: Tue, 29 Jul 2025 17:33:52 +0200 Subject: [PATCH 26/34] cm-1776: PR issues fixed --- ...ntentOmniChannelIdentityConfiguration.java | 5 ++- ...elIdentityProcessedAuctionRequestHook.java | 40 +++++++++---------- .../model/config/IdResResponseTest.java | 14 ++++--- ...entityProcessedAuctionRequestHookTest.java | 28 +++++-------- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index efc98d4d105..7eab97804cc 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -18,8 +18,9 @@ @Configuration @ConditionalOnProperty( - prefix = "hooks." + LiveIntentOmniChannelIdentityModule.CODE, name = "enabled", havingValue = "true" -) + prefix = "hooks." + LiveIntentOmniChannelIdentityModule.CODE, + name = "enabled", + havingValue = "true") public class LiveIntentOmniChannelIdentityConfiguration { @Bean diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index d1c6cba6d2f..421bdb4caee 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -19,10 +19,10 @@ import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.ListUtil; import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -49,31 +49,29 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( this.config = Objects.requireNonNull(config); this.mapper = Objects.requireNonNull(mapper); this.httpClient = Objects.requireNonNull(httpClient); - this.random = random; + this.random = Objects.requireNonNull(random); } @Override public Future> call( AuctionRequestPayload auctionRequestPayload, - AuctionInvocationContext invocationContext - ) { + AuctionInvocationContext invocationContext) { if (random.nextFloat() < config.getTreatmentRate()) { - final Future> update = requestEnrichment(auctionRequestPayload) - .map(resolutionResult -> + return requestEnrichment(auctionRequestPayload) + .>map(resolutionResult -> InvocationResultImpl.builder() .status(InvocationStatus.success) .action(InvocationAction.update) .payloadUpdate(requestPayload -> updatedPayload(requestPayload, resolutionResult)) - .build()); - - return update.onFailure(throwable -> logger.error("Failed enrichment:", throwable)); - } else { - return Future.succeededFuture( - InvocationResultImpl.builder() - .status(InvocationStatus.success) - .action(InvocationAction.no_action) - .build()); + .build()) + .onFailure(throwable -> logger.error("Failed enrichment:", throwable)); } + return Future.succeededFuture( + InvocationResultImpl.builder() + .status(InvocationStatus.success) + .action(InvocationAction.no_action) + .build()); + } private Future requestEnrichment(AuctionRequestPayload auctionRequestPayload) { @@ -96,13 +94,13 @@ private IdResResponse processResponse(HttpClientResponse response) { } private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayload, IdResResponse idResResponse) { - final BidRequest bidRequest = Optional.ofNullable( - requestPayload.bidRequest()).orElse(BidRequest.builder().build()); - final User user = Optional.ofNullable(bidRequest.getUser()).orElse(User.builder().build()); + final User user = Optional.ofNullable( + requestPayload.bidRequest()) + .map(BidRequest::getUser) + .orElse(User.builder().build()); - final List allEids = new ArrayList<>(); - allEids.addAll(Optional.ofNullable(user.getEids()).orElse(Collections.emptyList())); - allEids.addAll(idResResponse.getEids()); + final List allEids = ListUtil.union( + Optional.ofNullable(user.getEids()).orElse(Collections.emptyList()), idResResponse.getEids()); final User updatedUser = user.toBuilder().eids(allEids).build(); final BidRequest updatedBidRequest = requestPayload.bidRequest().toBuilder().user(updatedUser).build(); diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java index d53854e7eea..aa073979b34 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java @@ -1,11 +1,15 @@ package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config; import com.fasterxml.jackson.databind.ObjectMapper; +import com.iab.openrtb.request.Eid; +import com.iab.openrtb.request.Uid; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.IdResResponse; import org.prebid.server.json.JacksonMapper; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; public class IdResResponseTest { @@ -27,10 +31,10 @@ public void shouldDecodeFromString() { IdResResponse.class); // when and then - assertThat(result.getEids()).hasSize(1); - assertThat(result.getEids().getFirst().getSource()).isEqualTo("liveintent.com"); - assertThat(result.getEids().getFirst().getUids()).hasSize(1); - assertThat(result.getEids().getFirst().getUids().getFirst().getAtype()).isEqualTo(3); - assertThat(result.getEids().getFirst().getUids().getFirst().getId()).isEqualTo("some_id"); + assertThat(result.getEids()).isEqualTo(List.of( + Eid.builder() + .source("liveintent.com") + .uids(List.of(Uid.builder().atype(3).id("some_id").build())) + .build())); } } diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index f454fd2ce99..57f0d926bb1 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -48,6 +48,13 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest { @Mock private Random random; + private final ArgumentMatcher bearerAuthHeaderMatcher = new ArgumentMatcher<>() { + @Override + public boolean matches(MultiMap entries) { + return entries.contains("Authorization", "Bearer " + moduleConfig.getAuthToken(), true); + } + }; + @BeforeEach public void setUp() { final ObjectMapper mapper = new ObjectMapper(); @@ -61,6 +68,7 @@ public void setUp() { target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( moduleConfig, jacksonMapper, httpClient, random); + } @Test @@ -95,12 +103,7 @@ public void shouldAddResolvedEids() { when( httpClient.post( eq(moduleConfig.getIdentityResolutionEndpoint()), - argThat(new ArgumentMatcher() { - @Override - public boolean matches(MultiMap entries) { - return entries.contains("Authorization", "Bearer " + moduleConfig.getAuthToken(), true); - } - }), + argThat(bearerAuthHeaderMatcher), eq(jacksonMapper.encodeToString(bidRequest)), eq(moduleConfig.getRequestTimeoutMs()) ) @@ -111,9 +114,7 @@ public boolean matches(MultiMap entries) { final InvocationResult result = future.result(); // then - assertThat(future).isNotNull(); assertThat(future.succeeded()).isTrue(); - assertThat(result).isNotNull(); assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)) @@ -141,9 +142,7 @@ public void shouldNotAttemptToResolveEids() { final InvocationResult result = future.result(); // then - 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.payloadUpdate()).isNull(); @@ -176,12 +175,7 @@ public void shouldCreateUserWhenNotPresent() { when( httpClient.post( eq(moduleConfig.getIdentityResolutionEndpoint()), - argThat(new ArgumentMatcher() { - @Override - public boolean matches(MultiMap entries) { - return entries.contains("Authorization", "Bearer " + moduleConfig.getAuthToken(), true); - } - }), + argThat(bearerAuthHeaderMatcher), eq(jacksonMapper.encodeToString(bidRequest)), eq(moduleConfig.getRequestTimeoutMs()) ) @@ -192,9 +186,7 @@ public boolean matches(MultiMap entries) { final InvocationResult result = future.result(); // then - assertThat(future).isNotNull(); assertThat(future.succeeded()).isTrue(); - assertThat(result).isNotNull(); assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); assertThat(result.payloadUpdate() From b61986a2a7bfba41e0727ab95f121bffd76f0ffb Mon Sep 17 00:00:00 2001 From: ilya Date: Tue, 5 Aug 2025 17:07:00 +0200 Subject: [PATCH 27/34] cm-1776: PR issues fixed --- ...annelIdentityProcessedAuctionRequestHookTest.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index 57f0d926bb1..a01fc949ce2 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -100,13 +100,11 @@ public void shouldAddResolvedEids() { + ", \"id\" : \"" + enrichedUid.getId() + "\" } ] } ] }"); - when( - httpClient.post( - eq(moduleConfig.getIdentityResolutionEndpoint()), - argThat(bearerAuthHeaderMatcher), - eq(jacksonMapper.encodeToString(bidRequest)), - eq(moduleConfig.getRequestTimeoutMs()) - ) + when(httpClient.post( + eq(moduleConfig.getIdentityResolutionEndpoint()), + argThat(bearerAuthHeaderMatcher), + eq(jacksonMapper.encodeToString(bidRequest)), + eq(moduleConfig.getRequestTimeoutMs())) ).thenReturn(Future.succeededFuture(mockResponse)); final Future> future = From e458a4c59d62ab06e713c4e9a203c4e426a216c3 Mon Sep 17 00:00:00 2001 From: ilya Date: Tue, 5 Aug 2025 17:13:30 +0200 Subject: [PATCH 28/34] cm-1776: PR issues fixed --- extra/modules/live-intent-omni-channel-identity/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/modules/live-intent-omni-channel-identity/pom.xml b/extra/modules/live-intent-omni-channel-identity/pom.xml index 95863109ecd..7ed184a262d 100644 --- a/extra/modules/live-intent-omni-channel-identity/pom.xml +++ b/extra/modules/live-intent-omni-channel-identity/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 3.27.0-SNAPSHOT + 3.30.0-SNAPSHOT live-intent-omni-channel-identity From bf7d54aeec40dfe3aa6bf056f3d24032fc30c051 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Fri, 8 Aug 2025 11:39:00 +0200 Subject: [PATCH 29/34] LiveIntent Omni Channel Module Refactoring --- ...ntentOmniChannelIdentityConfiguration.java | 22 +- ...a => LiveIntentOmniChannelProperties.java} | 2 +- ...elIdentityProcessedAuctionRequestHook.java | 86 +++--- .../model/config/IdResResponseTest.java | 40 --- .../model/config/ModuleConfigTest.java | 35 --- ...entityProcessedAuctionRequestHookTest.java | 248 ++++++++++-------- 6 files changed, 197 insertions(+), 236 deletions(-) rename extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/{ModuleConfig.java => LiveIntentOmniChannelProperties.java} (81%) delete mode 100644 extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java delete mode 100644 extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index 7eab97804cc..c20ac612358 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -1,10 +1,8 @@ package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.config; -import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.ModuleConfig; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.LiveIntentOmniChannelProperties; import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1.LiveIntentOmniChannelIdentityModule; import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1.hooks.LiveIntentOmniChannelIdentityProcessedAuctionRequestHook; -import org.prebid.server.hooks.v1.Hook; -import org.prebid.server.hooks.v1.InvocationContext; import org.prebid.server.hooks.v1.Module; import org.prebid.server.json.JacksonMapper; import org.prebid.server.vertx.httpclient.HttpClient; @@ -13,7 +11,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Set; +import java.util.Collections; import java.util.concurrent.ThreadLocalRandom; @Configuration @@ -25,15 +23,19 @@ public class LiveIntentOmniChannelIdentityConfiguration { @Bean @ConfigurationProperties(prefix = "hooks.modules." + LiveIntentOmniChannelIdentityModule.CODE) - ModuleConfig moduleConfig() { - return new ModuleConfig(); + LiveIntentOmniChannelProperties properties() { + return new LiveIntentOmniChannelProperties(); } @Bean - Module liveIntentOmniChannelIdentityModule(ModuleConfig config, JacksonMapper mapper, HttpClient httpClient) { - final Set> hooks = Set.of( + Module liveIntentOmniChannelIdentityModule(LiveIntentOmniChannelProperties properties, + JacksonMapper mapper, + HttpClient httpClient) { + + final LiveIntentOmniChannelIdentityProcessedAuctionRequestHook hook = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( - config, mapper, httpClient, () -> ThreadLocalRandom.current().nextLong())); - return new LiveIntentOmniChannelIdentityModule(hooks); + properties, mapper, httpClient, () -> ThreadLocalRandom.current().nextLong()); + + return new LiveIntentOmniChannelIdentityModule(Collections.singleton(hook)); } } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/LiveIntentOmniChannelProperties.java similarity index 81% rename from extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java rename to extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/LiveIntentOmniChannelProperties.java index a7fc92b1feb..b6a61b0ca8f 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfig.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/LiveIntentOmniChannelProperties.java @@ -3,7 +3,7 @@ import lombok.Data; @Data -public final class ModuleConfig { +public final class LiveIntentOmniChannelProperties { long requestTimeoutMs; diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 421bdb4caee..477919b94d8 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -8,7 +8,7 @@ import org.prebid.server.hooks.execution.v1.InvocationResultImpl; import org.prebid.server.hooks.execution.v1.auction.AuctionRequestPayloadImpl; import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.IdResResponse; -import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.ModuleConfig; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.LiveIntentOmniChannelProperties; import org.prebid.server.hooks.v1.InvocationAction; import org.prebid.server.hooks.v1.InvocationResult; import org.prebid.server.hooks.v1.InvocationStatus; @@ -23,7 +23,6 @@ import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -31,55 +30,46 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { - private static final Logger logger = - LoggerFactory.getLogger(LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.class); + private static final Logger logger = LoggerFactory.getLogger( + LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.class); private static final String CODE = "liveintent-omni-channel-identity-enrichment-hook"; - private final ModuleConfig config; + private final LiveIntentOmniChannelProperties config; private final JacksonMapper mapper; private final HttpClient httpClient; private final RandomGenerator random; - public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( - ModuleConfig config, - JacksonMapper mapper, - HttpClient httpClient, - RandomGenerator random) { + public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniChannelProperties config, + JacksonMapper mapper, + HttpClient httpClient, + RandomGenerator random) { this.config = Objects.requireNonNull(config); + //todo: maybe it's redundant, what do you think? + HttpUtil.validateUrlSyntax(config.getIdentityResolutionEndpoint()); this.mapper = Objects.requireNonNull(mapper); this.httpClient = Objects.requireNonNull(httpClient); this.random = Objects.requireNonNull(random); } @Override - public Future> call( - AuctionRequestPayload auctionRequestPayload, - AuctionInvocationContext invocationContext) { - if (random.nextFloat() < config.getTreatmentRate()) { - return requestEnrichment(auctionRequestPayload) - .>map(resolutionResult -> - InvocationResultImpl.builder() - .status(InvocationStatus.success) - .action(InvocationAction.update) - .payloadUpdate(requestPayload -> updatedPayload(requestPayload, resolutionResult)) - .build()) - .onFailure(throwable -> logger.error("Failed enrichment:", throwable)); - } - return Future.succeededFuture( - InvocationResultImpl.builder() - .status(InvocationStatus.success) - .action(InvocationAction.no_action) - .build()); + public Future> call(AuctionRequestPayload auctionRequestPayload, + AuctionInvocationContext invocationContext) { + + return config.getTreatmentRate() <= random.nextFloat() + ? noAction() + : requestIdentities(auctionRequestPayload.bidRequest()) + .>map(this::update) + //todo: is it find to just fail instead of rejection or no_action? + .onFailure(throwable -> logger.error("Failed enrichment:", throwable)); } - private Future requestEnrichment(AuctionRequestPayload auctionRequestPayload) { - final String bidRequestJson = mapper.encodeToString(auctionRequestPayload.bidRequest()); + private Future requestIdentities(BidRequest bidRequest) { return httpClient.post( config.getIdentityResolutionEndpoint(), headers(), - bidRequestJson, + mapper.encodeToString(bidRequest), config.getRequestTimeoutMs()) .map(this::processResponse); } @@ -89,23 +79,37 @@ private MultiMap headers() { .add(HttpUtil.AUTHORIZATION_HEADER, "Bearer " + config.getAuthToken()); } + //todo: no status check and proper error code handling private IdResResponse processResponse(HttpClientResponse response) { return mapper.decodeValue(response.getBody(), IdResResponse.class); } - private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayload, IdResResponse idResResponse) { - final User user = Optional.ofNullable( - requestPayload.bidRequest()) - .map(BidRequest::getUser) - .orElse(User.builder().build()); + private static Future> noAction() { + return Future.succeededFuture(InvocationResultImpl.builder() + .status(InvocationStatus.success) + .action(InvocationAction.no_action) + .build()); + } - final List allEids = ListUtil.union( - Optional.ofNullable(user.getEids()).orElse(Collections.emptyList()), idResResponse.getEids()); + private InvocationResultImpl update(IdResResponse resolutionResult) { + return InvocationResultImpl.builder() + .status(InvocationStatus.success) + .action(InvocationAction.update) + //todo: might eids be null? NPE is possible + .payloadUpdate(payload -> updatedPayload(payload, resolutionResult.getEids())) + .build(); + } - final User updatedUser = user.toBuilder().eids(allEids).build(); - final BidRequest updatedBidRequest = requestPayload.bidRequest().toBuilder().user(updatedUser).build(); + private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayload, List resolvedEids) { + final BidRequest bidRequest = requestPayload.bidRequest(); + final User updatedUser = Optional.ofNullable(bidRequest.getUser()) + .map(user -> user.toBuilder().eids(user.getEids() == null + ? resolvedEids + : ListUtil.union(user.getEids(), resolvedEids))) + .orElseGet(() -> User.builder().eids(resolvedEids)) + .build(); - return AuctionRequestPayloadImpl.of(updatedBidRequest); + return AuctionRequestPayloadImpl.of(bidRequest.toBuilder().user(updatedUser).build()); } @Override diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java deleted file mode 100644 index aa073979b34..00000000000 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/IdResResponseTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.iab.openrtb.request.Eid; -import com.iab.openrtb.request.Uid; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.IdResResponse; -import org.prebid.server.json.JacksonMapper; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class IdResResponseTest { - - private JacksonMapper jacksonMapper; - - @BeforeEach - public void setUp() { - final ObjectMapper mapper = new ObjectMapper(); - jacksonMapper = new JacksonMapper(mapper); - } - - @Test - public void shouldDecodeFromString() { - // given - final IdResResponse result = jacksonMapper.decodeValue( - "{\"eids\": [ { \"source\": \"liveintent.com\", " - + "\"uids\": [ { \"atype\": 3, \"id\" : \"some_id\" } ] } ] }", - IdResResponse.class); - - // when and then - assertThat(result.getEids()).isEqualTo(List.of( - Eid.builder() - .source("liveintent.com") - .uids(List.of(Uid.builder().atype(3).id("some_id").build())) - .build())); - } -} diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java deleted file mode 100644 index 39cfd34298e..00000000000 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/ModuleConfigTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ModuleConfigTest { - - @Test - public void shouldReturnRequestTimeoutMs() { - final ModuleConfig moduleConfig = new ModuleConfig(); - moduleConfig.setRequestTimeoutMs(5); - assertThat(moduleConfig.getRequestTimeoutMs()).isEqualTo(5); - } - - @Test - public void shouldReturnIdentityResolutionEndpoint() { - // given - final ModuleConfig moduleConfig = new ModuleConfig(); - moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); - - // when and then - assertThat(moduleConfig.getIdentityResolutionEndpoint()).isEqualTo("https://test.com/idres"); - } - - @Test - public void shouldReturnAuthToken() { - // given - final ModuleConfig moduleConfig = new ModuleConfig(); - moduleConfig.setAuthToken("secret_token"); - - // when and then - assertThat(moduleConfig.getAuthToken()).isEqualTo("secret_token"); - } -} diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index a01fc949ce2..9a4b4fac776 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -1,21 +1,18 @@ package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1; -import com.fasterxml.jackson.databind.ObjectMapper; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Eid; import com.iab.openrtb.request.Uid; import com.iab.openrtb.request.User; import io.vertx.core.Future; -import io.vertx.core.MultiMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.hooks.execution.v1.auction.AuctionInvocationContextImpl; import org.prebid.server.hooks.execution.v1.auction.AuctionRequestPayloadImpl; -import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.ModuleConfig; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.LiveIntentOmniChannelProperties; import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1.hooks.LiveIntentOmniChannelIdentityProcessedAuctionRequestHook; import org.prebid.server.hooks.v1.InvocationAction; import org.prebid.server.hooks.v1.InvocationResult; @@ -23,174 +20,207 @@ import org.prebid.server.hooks.v1.auction.AuctionInvocationContext; import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.json.ObjectMapperProvider; import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; -import java.util.Collections; import java.util.List; import java.util.Random; +import java.util.concurrent.TimeoutException; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mock.Strictness.LENIENT; +import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest { - private ModuleConfig moduleConfig; - private LiveIntentOmniChannelIdentityProcessedAuctionRequestHook target; - private JacksonMapper jacksonMapper; + private static final JacksonMapper MAPPER = new JacksonMapper(ObjectMapperProvider.mapper()); @Mock private HttpClient httpClient; - @Mock + + @Mock(strictness = LENIENT) private Random random; - private final ArgumentMatcher bearerAuthHeaderMatcher = new ArgumentMatcher<>() { - @Override - public boolean matches(MultiMap entries) { - return entries.contains("Authorization", "Bearer " + moduleConfig.getAuthToken(), true); - } - }; + @Mock(strictness = LENIENT) + private LiveIntentOmniChannelProperties properties; + + private LiveIntentOmniChannelIdentityProcessedAuctionRequestHook target; @BeforeEach public void setUp() { - final ObjectMapper mapper = new ObjectMapper(); - jacksonMapper = new JacksonMapper(mapper); - - moduleConfig = new ModuleConfig(); - moduleConfig.setRequestTimeoutMs(5); - moduleConfig.setIdentityResolutionEndpoint("https://test.com/idres"); - moduleConfig.setAuthToken("secret_auth_token"); - moduleConfig.setTreatmentRate(0.9f); + given(properties.getRequestTimeoutMs()).willReturn(5L); + given(properties.getIdentityResolutionEndpoint()).willReturn("https://test.com/idres"); + given(properties.getAuthToken()).willReturn("auth_token"); + given(properties.getTreatmentRate()).willReturn(0.9f); + given(random.nextFloat()).willReturn(0.89f); - target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( - moduleConfig, jacksonMapper, httpClient, random); + target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(properties, MAPPER, httpClient, random); + } + @Test + public void creationShouldFailOnInvalidIdentityUrl() { + given(properties.getIdentityResolutionEndpoint()).willReturn("invalid_url"); + assertThatIllegalArgumentException().isThrownBy(() -> + new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(properties, MAPPER, httpClient, random)); } @Test - public void shouldAddResolvedEids() { + public void callShouldEnrichUserEidsWithRequestedEids() { // given - final Uid providedUid = Uid.builder().id("id1").atype(2).build(); - final Eid providedEid = Eid.builder().source("some.source.com") - .uids(Collections.singletonList(providedUid)).build(); + final Uid givenUid = Uid.builder().id("id1").atype(2).build(); + final Eid givenEid = Eid.builder().source("some.source.com").uids(singletonList(givenUid)).build(); + final User givenUser = User.builder().eids(singletonList(givenEid)).build(); + final BidRequest givenBidRequest = BidRequest.builder().id("request").user(givenUser).build(); + + final String givenResponseBody = """ + { + "eids": [{ + "source": "liveintent.com", + "uids": [{ + "atype": 3, + "id": "id2" + }] + }] + }"""; + + given(httpClient.post(any(), any(), any(), anyLong())) + .willReturn(Future.succeededFuture(HttpClientResponse.of(200, null, givenResponseBody))); + + final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( + null, null, false, null, null); + + // when + final InvocationResult result = + target.call(AuctionRequestPayloadImpl.of(givenBidRequest), auctionInvocationContext).result(); + + // then + final Eid expectedEid = Eid.builder() + .source("liveintent.com") + .uids(singletonList(Uid.builder().id("id2").atype(3).build())) + .build(); - final Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); - final Eid enrichedEid = Eid.builder().source("liveintent.com") - .uids(Collections.singletonList(enrichedUid)).build(); + assertThat(result.status()).isEqualTo(InvocationStatus.success); + assertThat(result.action()).isEqualTo(InvocationAction.update); + assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(givenBidRequest))) + .extracting(AuctionRequestPayload::bidRequest) + .extracting(BidRequest::getUser) + .extracting(User::getEids) + .isEqualTo(List.of(givenEid, expectedEid)); + + + verify(httpClient).post( + eq("https://test.com/idres"), + argThat(headers -> headers.contains("Authorization", "Bearer auth_token", true)), + eq(MAPPER.encodeToString(givenBidRequest)), + eq(5L)); + } - final User user = User.builder().eids(Collections.singletonList(providedEid)).build(); - final BidRequest bidRequest = BidRequest.builder().id("request").user(user).build(); + @Test + public void callShouldCreateUserAndUseRequestedEidsWhenUserIsAbsent() { + // given + final BidRequest givenBidRequest = BidRequest.builder().id("request").user(null).build(); + + final String givenResponseBody = """ + { + "eids": [{ + "source": "liveintent.com", + "uids": [{ + "atype": 3, + "id": "id2" + }] + }] + }"""; + + given(httpClient.post(any(), any(), any(), anyLong())) + .willReturn(Future.succeededFuture(HttpClientResponse.of(200, null, givenResponseBody))); final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( null, null, false, null, null); - final HttpClientResponse mockResponse = mock(HttpClientResponse.class); - // when - when(random.nextFloat()).thenReturn(0.89f); - - when(mockResponse.getBody()) - .thenReturn("{\"eids\": [ { \"source\": \"" + enrichedEid.getSource() - + "\", \"uids\": [ { \"atype\": " - + enrichedUid.getAtype() - + ", \"id\" : \"" - + enrichedUid.getId() + "\" } ] } ] }"); - - when(httpClient.post( - eq(moduleConfig.getIdentityResolutionEndpoint()), - argThat(bearerAuthHeaderMatcher), - eq(jacksonMapper.encodeToString(bidRequest)), - eq(moduleConfig.getRequestTimeoutMs())) - ).thenReturn(Future.succeededFuture(mockResponse)); - - final Future> future = - target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); - final InvocationResult result = future.result(); + final InvocationResult result = + target.call(AuctionRequestPayloadImpl.of(givenBidRequest), auctionInvocationContext).result(); // then - assertThat(future.succeeded()).isTrue(); + final Eid expectedEid = Eid.builder() + .source("liveintent.com") + .uids(singletonList(Uid.builder().id("id2").atype(3).build())) + .build(); + assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); - assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(bidRequest)) - .bidRequest().getUser().getEids()).isEqualTo(List.of(providedEid, enrichedEid)); + assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(givenBidRequest))) + .extracting(AuctionRequestPayload::bidRequest) + .extracting(BidRequest::getUser) + .extracting(User::getEids) + .isEqualTo(List.of(expectedEid)); + + verify(httpClient).post( + eq("https://test.com/idres"), + argThat(headers -> headers.contains("Authorization", "Bearer auth_token", true)), + eq(MAPPER.encodeToString(givenBidRequest)), + eq(5L)); } @Test - public void shouldNotAttemptToResolveEids() { + public void callShouldReturnNoActionSuccessfullyWhenTreatmentRateIsLowerThanThreshold() { // given - final Uid providedUid = Uid.builder().id("id1").atype(2).build(); - final Eid providedEid = Eid.builder().source("some.source.com") - .uids(Collections.singletonList(providedUid)).build(); - - final User user = User.builder().eids(Collections.singletonList(providedEid)).build(); - final BidRequest bidRequest = BidRequest.builder().id("request").user(user).build(); + final Uid givenUid = Uid.builder().id("id1").atype(2).build(); + final Eid givebEid = Eid.builder().source("some.source.com").uids(singletonList(givenUid)).build(); + final User givenUser = User.builder().eids(singletonList(givebEid)).build(); + final BidRequest givenBidRequest = BidRequest.builder().id("request").user(givenUser).build(); final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( null, null, false, null, null); - // when - when(random.nextFloat()).thenReturn(0.91f); + given(properties.getTreatmentRate()).willReturn(0.9f); + given(random.nextFloat()).willReturn(0.91f); - final Future> future = - target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); - final InvocationResult result = future.result(); + // when + final InvocationResult result = target.call( + AuctionRequestPayloadImpl.of(givenBidRequest), + auctionInvocationContext) + .result(); // then - assertThat(future.succeeded()).isTrue(); assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.no_action); assertThat(result.payloadUpdate()).isNull(); } @Test - public void shouldCreateUserWhenNotPresent() { + public void callShouldReturnFailureWhenRequestingEidsIsFailed() { // given - final Uid enrichedUid = Uid.builder().id("id2").atype(3).build(); - final Eid enrichedEid = Eid.builder().source("liveintent.com") - .uids(Collections.singletonList(enrichedUid)).build(); - - final BidRequest bidRequest = BidRequest.builder().id("request").build(); + final Uid givenUid = Uid.builder().id("id1").atype(2).build(); + final Eid givebEid = Eid.builder().source("some.source.com").uids(singletonList(givenUid)).build(); + final User givenUser = User.builder().eids(singletonList(givebEid)).build(); + final BidRequest givenBidRequest = BidRequest.builder().id("request").user(givenUser).build(); final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( null, null, false, null, null); - final HttpClientResponse mockResponse = mock(HttpClientResponse.class); + given(httpClient.post(any(), any(), any(), anyLong())) + .willReturn(Future.failedFuture(new TimeoutException("Timeout exceeded"))); // when - when(random.nextFloat()).thenReturn(0.89f); - - when(mockResponse.getBody()) - .thenReturn("{\"eids\": [{ \"source\": \"" - + enrichedEid.getSource() - + "\", \"uids\": [{ \"atype\": " - + enrichedUid.getAtype() + ", \"id\" : \"" - + enrichedUid.getId() + "\" }]}]}"); - - when( - httpClient.post( - eq(moduleConfig.getIdentityResolutionEndpoint()), - argThat(bearerAuthHeaderMatcher), - eq(jacksonMapper.encodeToString(bidRequest)), - eq(moduleConfig.getRequestTimeoutMs()) - ) - ).thenReturn(Future.succeededFuture(mockResponse)); - - final Future> future - = target.call(AuctionRequestPayloadImpl.of(bidRequest), auctionInvocationContext); - final InvocationResult result = future.result(); + final Future> result = target.call( + AuctionRequestPayloadImpl.of(givenBidRequest), + auctionInvocationContext); // then - assertThat(future.succeeded()).isTrue(); - assertThat(result.status()).isEqualTo(InvocationStatus.success); - assertThat(result.action()).isEqualTo(InvocationAction.update); - assertThat(result.payloadUpdate() - .apply(AuctionRequestPayloadImpl.of(bidRequest)) - .bidRequest() - .getUser() - .getEids()).isEqualTo(Collections.singletonList(enrichedEid)); + assertThat(result.failed()).isTrue(); + assertThat(result.cause()).isInstanceOf(TimeoutException.class); + assertThat(result.cause()) + .isInstanceOf(TimeoutException.class) + .hasMessage("Timeout exceeded"); } } From 88d0bc896d618b39314bf75b72433cda2c1ae320 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Fri, 8 Aug 2025 11:49:55 +0200 Subject: [PATCH 30/34] Fix checkstyle --- ...iveIntentOmniChannelIdentityProcessedAuctionRequestHook.java | 2 +- ...ntentOmniChannelIdentityProcessedAuctionRequestHookTest.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 477919b94d8..98dce2ed671 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -60,7 +60,7 @@ public Future> call(AuctionRequestPayloa ? noAction() : requestIdentities(auctionRequestPayload.bidRequest()) .>map(this::update) - //todo: is it find to just fail instead of rejection or no_action? + //todo: is it find to just fail instead of rejection or no_action? .onFailure(throwable -> logger.error("Failed enrichment:", throwable)); } diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index 9a4b4fac776..0d18b10ac4a 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -116,7 +116,6 @@ public void callShouldEnrichUserEidsWithRequestedEids() { .extracting(User::getEids) .isEqualTo(List.of(givenEid, expectedEid)); - verify(httpClient).post( eq("https://test.com/idres"), argThat(headers -> headers.contains("Authorization", "Bearer auth_token", true)), From 53a6e6f8370e772ae8f0aac21d82e97c7269e216 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Fri, 8 Aug 2025 11:52:39 +0200 Subject: [PATCH 31/34] Fix version --- extra/modules/live-intent-omni-channel-identity/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/modules/live-intent-omni-channel-identity/pom.xml b/extra/modules/live-intent-omni-channel-identity/pom.xml index 7ed184a262d..8b64db27a7d 100644 --- a/extra/modules/live-intent-omni-channel-identity/pom.xml +++ b/extra/modules/live-intent-omni-channel-identity/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 3.30.0-SNAPSHOT + 3.31.0-SNAPSHOT live-intent-omni-channel-identity From 4d6a603a30a7e26fb1a2bb867b7c2dbf426d2644 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Fri, 8 Aug 2025 15:39:22 +0200 Subject: [PATCH 32/34] Fix comments --- .../channel/identity/model/IdResResponse.java | 2 + ...elIdentityProcessedAuctionRequestHook.java | 12 ++--- ...entityProcessedAuctionRequestHookTest.java | 45 ++++++------------- 3 files changed, 19 insertions(+), 40 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java index c94df691c2f..35b22adca0d 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/IdResResponse.java @@ -1,6 +1,7 @@ package org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model; import com.iab.openrtb.request.Eid; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -8,6 +9,7 @@ @Data @NoArgsConstructor +@AllArgsConstructor(staticName = "of") public class IdResResponse { List eids; diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 98dce2ed671..b6b1b4ffa8d 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -5,6 +5,7 @@ import com.iab.openrtb.request.User; import io.vertx.core.Future; import io.vertx.core.MultiMap; +import org.apache.commons.collections4.ListUtils; import org.prebid.server.hooks.execution.v1.InvocationResultImpl; import org.prebid.server.hooks.execution.v1.auction.AuctionRequestPayloadImpl; import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.IdResResponse; @@ -45,7 +46,6 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniCh RandomGenerator random) { this.config = Objects.requireNonNull(config); - //todo: maybe it's redundant, what do you think? HttpUtil.validateUrlSyntax(config.getIdentityResolutionEndpoint()); this.mapper = Objects.requireNonNull(mapper); this.httpClient = Objects.requireNonNull(httpClient); @@ -60,7 +60,6 @@ public Future> call(AuctionRequestPayloa ? noAction() : requestIdentities(auctionRequestPayload.bidRequest()) .>map(this::update) - //todo: is it find to just fail instead of rejection or no_action? .onFailure(throwable -> logger.error("Failed enrichment:", throwable)); } @@ -79,7 +78,6 @@ private MultiMap headers() { .add(HttpUtil.AUTHORIZATION_HEADER, "Bearer " + config.getAuthToken()); } - //todo: no status check and proper error code handling private IdResResponse processResponse(HttpClientResponse response) { return mapper.decodeValue(response.getBody(), IdResResponse.class); } @@ -95,18 +93,16 @@ private InvocationResultImpl update(IdResResponse resolut return InvocationResultImpl.builder() .status(InvocationStatus.success) .action(InvocationAction.update) - //todo: might eids be null? NPE is possible .payloadUpdate(payload -> updatedPayload(payload, resolutionResult.getEids())) .build(); } private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayload, List resolvedEids) { + final List eids = ListUtils.emptyIfNull(resolvedEids); final BidRequest bidRequest = requestPayload.bidRequest(); final User updatedUser = Optional.ofNullable(bidRequest.getUser()) - .map(user -> user.toBuilder().eids(user.getEids() == null - ? resolvedEids - : ListUtil.union(user.getEids(), resolvedEids))) - .orElseGet(() -> User.builder().eids(resolvedEids)) + .map(user -> user.toBuilder().eids(ListUtil.union(ListUtils.emptyIfNull(user.getEids()), eids))) + .orElseGet(() -> User.builder().eids(eids)) .build(); return AuctionRequestPayloadImpl.of(bidRequest.toBuilder().user(updatedUser).build()); diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index 0d18b10ac4a..f661739e532 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -12,6 +12,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.hooks.execution.v1.auction.AuctionInvocationContextImpl; import org.prebid.server.hooks.execution.v1.auction.AuctionRequestPayloadImpl; +import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.IdResResponse; import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.model.config.LiveIntentOmniChannelProperties; import org.prebid.server.hooks.modules.liveintent.omni.channel.identity.v1.hooks.LiveIntentOmniChannelIdentityProcessedAuctionRequestHook; import org.prebid.server.hooks.v1.InvocationAction; @@ -81,19 +82,14 @@ public void callShouldEnrichUserEidsWithRequestedEids() { final User givenUser = User.builder().eids(singletonList(givenEid)).build(); final BidRequest givenBidRequest = BidRequest.builder().id("request").user(givenUser).build(); - final String givenResponseBody = """ - { - "eids": [{ - "source": "liveintent.com", - "uids": [{ - "atype": 3, - "id": "id2" - }] - }] - }"""; + final Eid expectedEid = Eid.builder() + .source("liveintent.com") + .uids(singletonList(Uid.builder().id("id2").atype(3).build())) + .build(); + final String responseBody = MAPPER.encodeToString(IdResResponse.of(List.of(expectedEid))); given(httpClient.post(any(), any(), any(), anyLong())) - .willReturn(Future.succeededFuture(HttpClientResponse.of(200, null, givenResponseBody))); + .willReturn(Future.succeededFuture(HttpClientResponse.of(200, null, responseBody))); final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( null, null, false, null, null); @@ -103,11 +99,6 @@ public void callShouldEnrichUserEidsWithRequestedEids() { target.call(AuctionRequestPayloadImpl.of(givenBidRequest), auctionInvocationContext).result(); // then - final Eid expectedEid = Eid.builder() - .source("liveintent.com") - .uids(singletonList(Uid.builder().id("id2").atype(3).build())) - .build(); - assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(givenBidRequest))) @@ -128,19 +119,14 @@ public void callShouldCreateUserAndUseRequestedEidsWhenUserIsAbsent() { // given final BidRequest givenBidRequest = BidRequest.builder().id("request").user(null).build(); - final String givenResponseBody = """ - { - "eids": [{ - "source": "liveintent.com", - "uids": [{ - "atype": 3, - "id": "id2" - }] - }] - }"""; + final Eid expectedEid = Eid.builder() + .source("liveintent.com") + .uids(singletonList(Uid.builder().id("id2").atype(3).build())) + .build(); + final String responseBody = MAPPER.encodeToString(IdResResponse.of(List.of(expectedEid))); given(httpClient.post(any(), any(), any(), anyLong())) - .willReturn(Future.succeededFuture(HttpClientResponse.of(200, null, givenResponseBody))); + .willReturn(Future.succeededFuture(HttpClientResponse.of(200, null, responseBody))); final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( null, null, false, null, null); @@ -150,11 +136,6 @@ public void callShouldCreateUserAndUseRequestedEidsWhenUserIsAbsent() { target.call(AuctionRequestPayloadImpl.of(givenBidRequest), auctionInvocationContext).result(); // then - final Eid expectedEid = Eid.builder() - .source("liveintent.com") - .uids(singletonList(Uid.builder().id("id2").atype(3).build())) - .build(); - assertThat(result.status()).isEqualTo(InvocationStatus.success); assertThat(result.action()).isEqualTo(InvocationAction.update); assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(givenBidRequest))) From cc3e0920be445802618d033bb73816532a1e5e8d Mon Sep 17 00:00:00 2001 From: antonbabak Date: Tue, 12 Aug 2025 10:47:18 +0200 Subject: [PATCH 33/34] fix comments --- ...veIntentOmniChannelIdentityConfiguration.java | 6 ++++-- ...annelIdentityProcessedAuctionRequestHook.java | 16 ++++++++++------ ...lIdentityProcessedAuctionRequestHookTest.java | 6 ++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index c20ac612358..61750b3b20b 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -6,6 +6,7 @@ import org.prebid.server.hooks.v1.Module; import org.prebid.server.json.JacksonMapper; import org.prebid.server.vertx.httpclient.HttpClient; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -30,11 +31,12 @@ LiveIntentOmniChannelProperties properties() { @Bean Module liveIntentOmniChannelIdentityModule(LiveIntentOmniChannelProperties properties, JacksonMapper mapper, - HttpClient httpClient) { + HttpClient httpClient, + @Value("${logging.sampling-rate:0.01}") double logSamplingRate) { final LiveIntentOmniChannelIdentityProcessedAuctionRequestHook hook = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( - properties, mapper, httpClient, () -> ThreadLocalRandom.current().nextLong()); + properties, mapper, httpClient, () -> ThreadLocalRandom.current().nextLong(), logSamplingRate); return new LiveIntentOmniChannelIdentityModule(Collections.singleton(hook)); } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index b6b1b4ffa8d..55cbffc6dd8 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -17,7 +17,7 @@ import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; import org.prebid.server.hooks.v1.auction.ProcessedAuctionRequestHook; import org.prebid.server.json.JacksonMapper; -import org.prebid.server.log.Logger; +import org.prebid.server.log.ConditionalLogger; import org.prebid.server.log.LoggerFactory; import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ListUtil; @@ -31,25 +31,29 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { - private static final Logger logger = LoggerFactory.getLogger( - LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.class); + private static final ConditionalLogger conditionalLogger = new ConditionalLogger(LoggerFactory.getLogger( + LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.class)); + private static final String CODE = "liveintent-omni-channel-identity-enrichment-hook"; private final LiveIntentOmniChannelProperties config; private final JacksonMapper mapper; private final HttpClient httpClient; private final RandomGenerator random; + private final double logSamplingRate; public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniChannelProperties config, JacksonMapper mapper, HttpClient httpClient, - RandomGenerator random) { + RandomGenerator random, + double logSamplingRate) { this.config = Objects.requireNonNull(config); HttpUtil.validateUrlSyntax(config.getIdentityResolutionEndpoint()); this.mapper = Objects.requireNonNull(mapper); this.httpClient = Objects.requireNonNull(httpClient); this.random = Objects.requireNonNull(random); + this.logSamplingRate = logSamplingRate; } @Override @@ -60,8 +64,8 @@ public Future> call(AuctionRequestPayloa ? noAction() : requestIdentities(auctionRequestPayload.bidRequest()) .>map(this::update) - .onFailure(throwable -> logger.error("Failed enrichment:", throwable)); - + .onFailure(throwable -> conditionalLogger.error( + "Failed enrichment: %s".formatted(throwable.getMessage()), logSamplingRate)); } private Future requestIdentities(BidRequest bidRequest) { diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index f661739e532..c83e223e508 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -64,14 +64,16 @@ public void setUp() { given(properties.getTreatmentRate()).willReturn(0.9f); given(random.nextFloat()).willReturn(0.89f); - target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(properties, MAPPER, httpClient, random); + target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( + properties, MAPPER, httpClient, random, 0.01d); } @Test public void creationShouldFailOnInvalidIdentityUrl() { given(properties.getIdentityResolutionEndpoint()).willReturn("invalid_url"); assertThatIllegalArgumentException().isThrownBy(() -> - new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(properties, MAPPER, httpClient, random)); + new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( + properties, MAPPER, httpClient, random, 0.01d)); } @Test From d8cb2faf0a962b5d46149fbd5400eb77dba45526 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Wed, 20 Aug 2025 14:02:01 +0200 Subject: [PATCH 34/34] Fix comments --- ...LiveIntentOmniChannelIdentityConfiguration.java | 3 +-- ...ChannelIdentityProcessedAuctionRequestHook.java | 13 +++++-------- ...nelIdentityProcessedAuctionRequestHookTest.java | 14 ++++---------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java index 61750b3b20b..e3f286e0120 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/config/LiveIntentOmniChannelIdentityConfiguration.java @@ -13,7 +13,6 @@ import org.springframework.context.annotation.Configuration; import java.util.Collections; -import java.util.concurrent.ThreadLocalRandom; @Configuration @ConditionalOnProperty( @@ -36,7 +35,7 @@ Module liveIntentOmniChannelIdentityModule(LiveIntentOmniChannelProperties prope final LiveIntentOmniChannelIdentityProcessedAuctionRequestHook hook = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( - properties, mapper, httpClient, () -> ThreadLocalRandom.current().nextLong(), logSamplingRate); + properties, mapper, httpClient, logSamplingRate); return new LiveIntentOmniChannelIdentityModule(Collections.singleton(hook)); } diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 55cbffc6dd8..5c3e43f9952 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -27,7 +27,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.random.RandomGenerator; +import java.util.concurrent.ThreadLocalRandom; public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook { @@ -39,20 +39,17 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements private final LiveIntentOmniChannelProperties config; private final JacksonMapper mapper; private final HttpClient httpClient; - private final RandomGenerator random; private final double logSamplingRate; public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniChannelProperties config, JacksonMapper mapper, HttpClient httpClient, - RandomGenerator random, double logSamplingRate) { this.config = Objects.requireNonNull(config); HttpUtil.validateUrlSyntax(config.getIdentityResolutionEndpoint()); this.mapper = Objects.requireNonNull(mapper); this.httpClient = Objects.requireNonNull(httpClient); - this.random = Objects.requireNonNull(random); this.logSamplingRate = logSamplingRate; } @@ -60,12 +57,12 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniCh public Future> call(AuctionRequestPayload auctionRequestPayload, AuctionInvocationContext invocationContext) { - return config.getTreatmentRate() <= random.nextFloat() - ? noAction() - : requestIdentities(auctionRequestPayload.bidRequest()) + return config.getTreatmentRate() > ThreadLocalRandom.current().nextFloat() + ? requestIdentities(auctionRequestPayload.bidRequest()) .>map(this::update) .onFailure(throwable -> conditionalLogger.error( - "Failed enrichment: %s".formatted(throwable.getMessage()), logSamplingRate)); + "Failed enrichment: %s".formatted(throwable.getMessage()), logSamplingRate)) + : noAction(); } private Future requestIdentities(BidRequest bidRequest) { diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index c83e223e508..9dc53916980 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -26,7 +26,6 @@ import org.prebid.server.vertx.httpclient.model.HttpClientResponse; import java.util.List; -import java.util.Random; import java.util.concurrent.TimeoutException; import static java.util.Collections.singletonList; @@ -48,9 +47,6 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest { @Mock private HttpClient httpClient; - @Mock(strictness = LENIENT) - private Random random; - @Mock(strictness = LENIENT) private LiveIntentOmniChannelProperties properties; @@ -61,11 +57,10 @@ public void setUp() { given(properties.getRequestTimeoutMs()).willReturn(5L); given(properties.getIdentityResolutionEndpoint()).willReturn("https://test.com/idres"); given(properties.getAuthToken()).willReturn("auth_token"); - given(properties.getTreatmentRate()).willReturn(0.9f); - given(random.nextFloat()).willReturn(0.89f); + given(properties.getTreatmentRate()).willReturn(1.0f); target = new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( - properties, MAPPER, httpClient, random, 0.01d); + properties, MAPPER, httpClient, 0.01d); } @Test @@ -73,7 +68,7 @@ public void creationShouldFailOnInvalidIdentityUrl() { given(properties.getIdentityResolutionEndpoint()).willReturn("invalid_url"); assertThatIllegalArgumentException().isThrownBy(() -> new LiveIntentOmniChannelIdentityProcessedAuctionRequestHook( - properties, MAPPER, httpClient, random, 0.01d)); + properties, MAPPER, httpClient, 0.01d)); } @Test @@ -164,8 +159,7 @@ public void callShouldReturnNoActionSuccessfullyWhenTreatmentRateIsLowerThanThre final AuctionInvocationContext auctionInvocationContext = AuctionInvocationContextImpl.of( null, null, false, null, null); - given(properties.getTreatmentRate()).willReturn(0.9f); - given(random.nextFloat()).willReturn(0.91f); + given(properties.getTreatmentRate()).willReturn(0.0f); // when final InvocationResult result = target.call(