diff --git a/extra/bundle/pom.xml b/extra/bundle/pom.xml
index 5d44255ca2d..a210a0919ee 100644
--- a/extra/bundle/pom.xml
+++ b/extra/bundle/pom.xml
@@ -5,7 +5,7 @@
org.prebid
prebid-server-aggregator
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
../../extra/pom.xml
diff --git a/extra/modules/confiant-ad-quality/pom.xml b/extra/modules/confiant-ad-quality/pom.xml
index 1d86482129b..e2f82de7886 100644
--- a/extra/modules/confiant-ad-quality/pom.xml
+++ b/extra/modules/confiant-ad-quality/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
confiant-ad-quality
diff --git a/extra/modules/fiftyone-devicedetection/pom.xml b/extra/modules/fiftyone-devicedetection/pom.xml
index aafbfa859ac..5c1dbb9ccc0 100644
--- a/extra/modules/fiftyone-devicedetection/pom.xml
+++ b/extra/modules/fiftyone-devicedetection/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
fiftyone-devicedetection
diff --git a/extra/modules/greenbids-real-time-data/pom.xml b/extra/modules/greenbids-real-time-data/pom.xml
index 141e4cf087e..f5ab8eb4b54 100644
--- a/extra/modules/greenbids-real-time-data/pom.xml
+++ b/extra/modules/greenbids-real-time-data/pom.xml
@@ -4,7 +4,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
greenbids-real-time-data
diff --git a/extra/modules/live-intent-omni-channel-identity/pom.xml b/extra/modules/live-intent-omni-channel-identity/pom.xml
index c0c6c463354..e846ccbdad6 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.39.0-SNAPSHOT
+ 3.40.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/config/LiveIntentOmniChannelProperties.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
index 01d37eabda0..383aacea3a9 100644
--- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/LiveIntentOmniChannelProperties.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
@@ -2,7 +2,7 @@
import lombok.Data;
-import java.util.List;
+import java.util.Set;
@Data
public final class LiveIntentOmniChannelProperties {
@@ -15,5 +15,5 @@ public final class LiveIntentOmniChannelProperties {
float treatmentRate;
- List targetBidders;
+ Set targetBidders;
}
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 32b608ce21c..3afdb146018 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
@@ -9,6 +9,7 @@
import io.vertx.core.MultiMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
+import org.apache.commons.collections4.SetUtils;
import org.prebid.server.activity.Activity;
import org.prebid.server.activity.ComponentType;
import org.prebid.server.activity.infrastructure.ActivityInfrastructure;
@@ -40,18 +41,15 @@
import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidDataEidPermissions;
import org.prebid.server.util.HttpUtil;
import org.prebid.server.util.ListUtil;
-import org.prebid.server.util.StreamUtil;
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;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook {
@@ -65,7 +63,7 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements
private final HttpClient httpClient;
private final UserFpdActivityMask userFpdActivityMask;
private final double logSamplingRate;
- private final List targetBidders;
+ private final Set targetBidders;
public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniChannelProperties config,
UserFpdActivityMask userFpdActivityMask,
@@ -79,7 +77,7 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniCh
this.httpClient = Objects.requireNonNull(httpClient);
this.logSamplingRate = logSamplingRate;
this.userFpdActivityMask = Objects.requireNonNull(userFpdActivityMask);
- this.targetBidders = ListUtils.emptyIfNull(config.getTargetBidders());
+ this.targetBidders = SetUtils.emptyIfNull(config.getTargetBidders());
}
@Override
@@ -202,7 +200,7 @@ private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayloa
}
private BidRequest updateAllowedBidders(BidRequest bidRequest, List resolvedEids) {
- if (targetBidders.isEmpty()) {
+ if (CollectionUtils.isEmpty(targetBidders) || CollectionUtils.isEmpty(resolvedEids)) {
return bidRequest;
}
@@ -210,6 +208,14 @@ private BidRequest updateAllowedBidders(BidRequest bidRequest, List resolve
final ExtRequestPrebid extPrebid = ext != null ? ext.getPrebid() : null;
final ExtRequestPrebidData extPrebidData = extPrebid != null ? extPrebid.getData() : null;
+ final List existingPerms = extPrebidData != null
+ ? extPrebidData.getEidPermissions()
+ : null;
+
+ if (CollectionUtils.isEmpty(existingPerms)) {
+ return bidRequest;
+ }
+
final ExtRequestPrebid updatedExtPrebid = Optional.ofNullable(extPrebid)
.map(ExtRequestPrebid::toBuilder)
.orElseGet(ExtRequestPrebid::builder)
@@ -225,35 +231,38 @@ private BidRequest updateAllowedBidders(BidRequest bidRequest, List resolve
}
private ExtRequestPrebidData updatePrebidData(ExtRequestPrebidData extPrebidData, List resolvedEids) {
- final List prebidDataBidders = extPrebidData != null ? extPrebidData.getBidders() : null;
- final List updatedPrebidDataBidders = prebidDataBidders != null
- ? (List) CollectionUtils.union(targetBidders, prebidDataBidders)
- : targetBidders;
-
- final Set resolvedSources = resolvedEids.stream().map(Eid::getSource).collect(Collectors.toSet());
-
- final List initialPermissions = Optional.ofNullable(extPrebidData)
- .map(ExtRequestPrebidData::getEidPermissions)
- .orElse(Collections.emptyList());
- final List updatedPermissions = Stream.concat(
- initialPermissions.stream()
- .map(permission -> updateEidPermission(permission, resolvedSources)),
- resolvedSources.stream()
- .map(source -> ExtRequestPrebidDataEidPermissions.of(source, targetBidders)))
- .filter(StreamUtil.distinctBy(ExtRequestPrebidDataEidPermissions::getSource))
+ final List originalBidders = extPrebidData != null ? extPrebidData.getBidders() : null;
+
+ final Set resolvedSources = resolvedEids.stream()
+ .map(Eid::getSource)
+ .collect(Collectors.toSet());
+
+ final List updatedPermissions = extPrebidData.getEidPermissions().stream()
+ .map(permission -> restrictEidPermission(permission, resolvedSources))
+ .filter(Objects::nonNull)
.toList();
- return ExtRequestPrebidData.of(updatedPrebidDataBidders, updatedPermissions);
+ return ExtRequestPrebidData.of(originalBidders, updatedPermissions);
}
- private ExtRequestPrebidDataEidPermissions updateEidPermission(ExtRequestPrebidDataEidPermissions permission,
- Set resolvedSources) {
+ private ExtRequestPrebidDataEidPermissions restrictEidPermission(ExtRequestPrebidDataEidPermissions permission,
+ Set resolvedSources) {
- return resolvedSources.contains(permission.getSource())
- ? ExtRequestPrebidDataEidPermissions.of(
- permission.getSource(),
- (List) CollectionUtils.union(permission.getBidders(), targetBidders))
- : permission;
+ if (!resolvedSources.contains(permission.getSource())) {
+ return permission;
+ }
+
+ final List finalBidders = ListUtils.emptyIfNull(permission.getBidders()).stream()
+ .filter(targetBidders::contains)
+ .toList();
+
+ return CollectionUtils.isEmpty(finalBidders)
+ ? null
+ : ExtRequestPrebidDataEidPermissions
+ .builder()
+ .bidders(finalBidders)
+ .source(permission.getSource())
+ .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 7b05ec6072d..4dfaa8c8df4 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
@@ -36,6 +36,7 @@
import org.prebid.server.vertx.httpclient.model.HttpClientResponse;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.TimeoutException;
import static java.util.Collections.singletonList;
@@ -74,11 +75,11 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest {
private LiveIntentOmniChannelIdentityProcessedAuctionRequestHook target;
- private List configuredBidders;
+ private Set configuredBidders;
@BeforeEach
public void setUp() {
- configuredBidders = List.of("bidder1", "bidder2");
+ configuredBidders = Set.of("bidder1", "bidder2");
given(properties.getRequestTimeoutMs()).willReturn(5L);
given(properties.getIdentityResolutionEndpoint()).willReturn("https://test.com/idres");
given(properties.getAuthToken()).willReturn("auth_token");
@@ -375,14 +376,38 @@ public void callShouldReturnFailureWhenRequestingEidsIsFailed() {
}
@Test
- public void biddersConfiguredRestrictionShouldBeRespected() {
+ public void shouldRestrictExistingEidPermissionsByIntersectionAndKeepGlobalBiddersUnchanged() {
+ // given
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 ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(configuredBidders, List.of(
- ExtRequestPrebidDataEidPermissions.of("liveintent.com", configuredBidders)));
+ final ExtRequestPrebidDataEidPermissions otherBidder = ExtRequestPrebidDataEidPermissions.builder()
+ .source("some.other-source.com")
+ .bidders(singletonList("bidderY"))
+ .build();
+
+ final ExtRequestPrebidDataEidPermissions liBidder2 = ExtRequestPrebidDataEidPermissions.builder()
+ .source("liveintent.com")
+ .bidders(singletonList("bidder2"))
+ .build();
+ final ExtRequestPrebidDataEidPermissions liBidder23 = ExtRequestPrebidDataEidPermissions.builder()
+ .source("liveintent.com")
+ .bidders(List.of("bidder2", "bidder3"))
+ .build();
+
+ final ExtRequestPrebidData givenData = ExtRequestPrebidData.of(singletonList("bidderX"),
+ List.of(otherBidder, liBidder23));
+
+ final BidRequest givenBidRequest = BidRequest.builder()
+ .id("request")
+ .user(givenUser)
+ .ext(ExtRequest.of(ExtRequestPrebid.builder().data(givenData).build()))
+ .build();
+
+ final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(
+ List.of("bidderX"),
+ List.of(otherBidder, liBidder2));
final Eid expectedEid = Eid.builder().source("liveintent.com").build();
@@ -418,23 +443,31 @@ public void biddersConfiguredRestrictionShouldBeRespected() {
}
@Test
- public void biddersConfiguredRestrictionShouldBeMergedWithProvided() {
+ public void shouldNotAddNewEidPermissionsOrModifyGlobalBiddersWhenSourceNotPresent() {
// given
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).ext(ExtRequest.of(
- ExtRequestPrebid.builder().data(ExtRequestPrebidData.of(List.of("bidder3"), List.of(
- ExtRequestPrebidDataEidPermissions.of("some.other-source.com", List.of("bidder3")),
- ExtRequestPrebidDataEidPermissions.of("some.source.com", List.of("bidder3"))))
- ).build())).build();
+ final ExtRequestPrebidDataEidPermissions bidder1 = ExtRequestPrebidDataEidPermissions.builder()
+ .source("some.other-source.com")
+ .bidders(singletonList("bidder3"))
+ .build();
+ final ExtRequestPrebidDataEidPermissions bidder2 = ExtRequestPrebidDataEidPermissions.builder()
+ .source("some.source.com")
+ .bidders(singletonList("bidder3"))
+ .build();
- final List expectedBidders = List.of("bidder3", "bidder2", "bidder1");
+ final List bidders = List.of(bidder1, bidder2);
- final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(expectedBidders, List.of(
- ExtRequestPrebidDataEidPermissions.of("some.other-source.com", List.of("bidder3")),
- ExtRequestPrebidDataEidPermissions.of("some.source.com", List.of("bidder3")),
- ExtRequestPrebidDataEidPermissions.of("liveintent.com", configuredBidders)));
+ final BidRequest givenBidRequest = BidRequest.builder()
+ .id("request")
+ .user(givenUser)
+ .ext(ExtRequest.of(ExtRequestPrebid.builder()
+ .data(ExtRequestPrebidData.of(singletonList("bidder3"), bidders))
+ .build()))
+ .build();
+
+ final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(List.of("bidder3"), bidders);
final Eid expectedEid = Eid.builder().source("liveintent.com").build();
@@ -468,4 +501,69 @@ public void biddersConfiguredRestrictionShouldBeMergedWithProvided() {
eq(MAPPER.encodeToString(givenBidRequest)),
eq(5L));
}
+
+ @Test
+ public void shouldRemovePermissionWhenIntersectionIsEmpty() {
+ // given
+ 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 ExtRequestPrebidData givenData = ExtRequestPrebidData.of(
+ List.of("bidderGlobal"),
+ List.of(
+ ExtRequestPrebidDataEidPermissions.builder()
+ .source("liveintent.com")
+ .bidders(singletonList("not-allowed"))
+ .build(),
+ ExtRequestPrebidDataEidPermissions.builder()
+ .source("keep.com")
+ .bidders(singletonList("bidderGlobal"))
+ .build()));
+
+ final BidRequest givenBidRequest = BidRequest.builder()
+ .id("request")
+ .user(givenUser)
+ .ext(ExtRequest.of(ExtRequestPrebid.builder().data(givenData).build()))
+ .build();
+
+ final Eid expectedEid = Eid.builder().source("liveintent.com").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, responseBody)));
+
+ given(auctionInvocationContext.auctionContext()).willReturn(auctionContext);
+ given(auctionContext.getActivityInfrastructure()).willReturn(activityInfrastructure);
+ given(activityInfrastructure.isAllowed(any(), any())).willReturn(true);
+ given(userFpdActivityMask.maskUser(any(), eq(false), eq(false)))
+ .willAnswer(invocation -> invocation.getArgument(0));
+ given(userFpdActivityMask.maskDevice(any(), eq(false), eq(false)))
+ .willAnswer(invocation -> invocation.getArgument(0));
+
+ // when
+ final InvocationResult result =
+ target.call(AuctionRequestPayloadImpl.of(givenBidRequest), auctionInvocationContext).result();
+
+ // then
+ final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(
+ List.of("bidderGlobal"),
+ List.of(ExtRequestPrebidDataEidPermissions.builder()
+ .source("keep.com")
+ .bidders(singletonList("bidderGlobal"))
+ .build()));
+
+ assertThat(result.status()).isEqualTo(InvocationStatus.success);
+ assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(givenBidRequest)))
+ .extracting(AuctionRequestPayload::bidRequest)
+ .extracting(BidRequest::getExt)
+ .extracting(ExtRequest::getPrebid)
+ .extracting(ExtRequestPrebid::getData)
+ .isEqualTo(expectedData);
+
+ verify(httpClient).post(
+ eq("https://test.com/idres"),
+ argThat(headers -> headers.contains("Authorization", "Bearer auth_token", true)),
+ eq(MAPPER.encodeToString(givenBidRequest)),
+ eq(5L));
+ }
}
diff --git a/extra/modules/optable-targeting/pom.xml b/extra/modules/optable-targeting/pom.xml
index 9e6503995c0..34278806fc8 100644
--- a/extra/modules/optable-targeting/pom.xml
+++ b/extra/modules/optable-targeting/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
optable-targeting
diff --git a/extra/modules/ortb2-blocking/pom.xml b/extra/modules/ortb2-blocking/pom.xml
index 55107ec2223..6aa8f9b2792 100644
--- a/extra/modules/ortb2-blocking/pom.xml
+++ b/extra/modules/ortb2-blocking/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
ortb2-blocking
diff --git a/extra/modules/pb-request-correction/pom.xml b/extra/modules/pb-request-correction/pom.xml
index 30fe61d6498..e1deb0518b8 100644
--- a/extra/modules/pb-request-correction/pom.xml
+++ b/extra/modules/pb-request-correction/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
pb-request-correction
diff --git a/extra/modules/pb-response-correction/pom.xml b/extra/modules/pb-response-correction/pom.xml
index faf24c6baba..09f08ce6d67 100644
--- a/extra/modules/pb-response-correction/pom.xml
+++ b/extra/modules/pb-response-correction/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
pb-response-correction
diff --git a/extra/modules/pb-richmedia-filter/pom.xml b/extra/modules/pb-richmedia-filter/pom.xml
index e8db972c01e..735704921f1 100644
--- a/extra/modules/pb-richmedia-filter/pom.xml
+++ b/extra/modules/pb-richmedia-filter/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
pb-richmedia-filter
diff --git a/extra/modules/pb-rule-engine/pom.xml b/extra/modules/pb-rule-engine/pom.xml
index 0d6d567a809..3fe12665358 100644
--- a/extra/modules/pb-rule-engine/pom.xml
+++ b/extra/modules/pb-rule-engine/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
pb-rule-engine
diff --git a/extra/modules/pom.xml b/extra/modules/pom.xml
index e18fe0f665e..d55994fd58c 100644
--- a/extra/modules/pom.xml
+++ b/extra/modules/pom.xml
@@ -5,7 +5,7 @@
org.prebid
prebid-server-aggregator
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
../../extra/pom.xml
diff --git a/extra/modules/wurfl-devicedetection/pom.xml b/extra/modules/wurfl-devicedetection/pom.xml
index 1068dc04cd4..dde02bed3ed 100644
--- a/extra/modules/wurfl-devicedetection/pom.xml
+++ b/extra/modules/wurfl-devicedetection/pom.xml
@@ -5,7 +5,7 @@
org.prebid.server.hooks.modules
all-modules
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
wurfl-devicedetection
diff --git a/extra/pom.xml b/extra/pom.xml
index 836df8f4a38..2cb81b6464a 100644
--- a/extra/pom.xml
+++ b/extra/pom.xml
@@ -4,7 +4,7 @@
org.prebid
prebid-server-aggregator
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
pom
@@ -33,7 +33,7 @@
10.17.0
- 3.5.5
+ 3.5.10
4.5.20
2.0.1.Final
4.4
diff --git a/pom.xml b/pom.xml
index b9f4a2eff8b..73513000b95 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.prebid
prebid-server-aggregator
- 3.39.0-SNAPSHOT
+ 3.40.0-SNAPSHOT
extra/pom.xml
diff --git a/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java b/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java
deleted file mode 100644
index 63ad320ca4e..00000000000
--- a/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java
+++ /dev/null
@@ -1,358 +0,0 @@
-package org.prebid.server.bidder.adocean;
-
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.iab.openrtb.request.App;
-import com.iab.openrtb.request.Banner;
-import com.iab.openrtb.request.BidRequest;
-import com.iab.openrtb.request.Device;
-import com.iab.openrtb.request.Format;
-import com.iab.openrtb.request.Imp;
-import com.iab.openrtb.request.Site;
-import com.iab.openrtb.request.User;
-import com.iab.openrtb.response.Bid;
-import io.vertx.core.MultiMap;
-import io.vertx.core.http.HttpMethod;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.MapUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.message.BasicNameValuePair;
-import org.prebid.server.bidder.Bidder;
-import org.prebid.server.bidder.adocean.model.AdoceanResponseAdUnit;
-import org.prebid.server.bidder.model.BidderBid;
-import org.prebid.server.bidder.model.BidderCall;
-import org.prebid.server.bidder.model.BidderError;
-import org.prebid.server.bidder.model.HttpRequest;
-import org.prebid.server.bidder.model.Result;
-import org.prebid.server.exception.PreBidException;
-import org.prebid.server.json.JacksonMapper;
-import org.prebid.server.proto.openrtb.ext.ExtPrebid;
-import org.prebid.server.proto.openrtb.ext.request.ExtUser;
-import org.prebid.server.proto.openrtb.ext.request.adocean.ExtImpAdocean;
-import org.prebid.server.proto.openrtb.ext.response.BidType;
-import org.prebid.server.util.HttpUtil;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.stream.Collectors;
-
-public class AdoceanBidder implements Bidder {
-
- private static final TypeReference> ADOCEAN_EXT_TYPE_REFERENCE =
- new TypeReference<>() {
- };
- private static final String VERSION = "1.3.0";
- private static final int MAX_URI_LENGTH = 8000;
- private static final String MEASUREMENT_CODE_TEMPLATE = """
- """;
-
- private final String endpointUrl;
- private final JacksonMapper mapper;
-
- public AdoceanBidder(String endpointUrl, JacksonMapper mapper) {
- this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
- this.mapper = Objects.requireNonNull(mapper);
- }
-
- @Override
- public Result>> makeHttpRequests(BidRequest request) {
- final List errors = new ArrayList<>();
- final User user = request.getUser();
- final ExtUser extUser = user != null ? user.getExt() : null;
- final String consentString = extUser != null ? extUser.getConsent() : "";
-
- final List> httpRequests = new ArrayList<>();
- for (Imp imp : request.getImp()) {
- try {
- final ExtImpAdocean extImpAdocean = parseImpExt(imp);
- validateImpExt(extImpAdocean);
-
- final Map slaveSizes = new HashMap<>();
- slaveSizes.put(extImpAdocean.getSlaveId(), getImpSizes(imp));
- if (addRequestAndCheckIfDuplicates(httpRequests, extImpAdocean, imp.getId(), slaveSizes,
- request.getTest())) {
- continue;
- }
- httpRequests.add(createSingleRequest(request, imp, extImpAdocean, consentString, slaveSizes));
- } catch (PreBidException e) {
- errors.add(BidderError.badInput(e.getMessage()));
- }
- }
-
- return Result.of(httpRequests, errors);
- }
-
- private ExtImpAdocean parseImpExt(Imp imp) {
- try {
- return mapper.mapper().convertValue(imp.getExt(), ADOCEAN_EXT_TYPE_REFERENCE).getBidder();
- } catch (IllegalArgumentException e) {
- throw new PreBidException(
- "Error parsing adOceanExt parameters, in imp with id : " + imp.getId());
- }
- }
-
- private static void validateImpExt(ExtImpAdocean impExt) {
- if (StringUtils.isEmpty(impExt.getEmitterPrefix())) {
- throw new PreBidException("No emitterPrefix param");
- }
- }
-
- private boolean addRequestAndCheckIfDuplicates(List> httpRequests, ExtImpAdocean extImpAdocean,
- String impid, Map slaveSizes, Integer test) {
- for (HttpRequest request : httpRequests) {
- try {
- final URIBuilder uriBuilder = new URIBuilder(request.getUri());
- final List queryParams = uriBuilder.getQueryParams();
-
- final String masterId = queryParams.stream()
- .filter(param -> "id".equals(param.getName()))
- .findFirst()
- .map(NameValuePair::getValue)
- .orElse(null);
-
- if (masterId != null && masterId.equals(extImpAdocean.getMasterId())) {
- final boolean isExistingSlaveId = queryParams.stream()
- .filter(param -> "aid".equals(param.getName()))
- .map(param -> param.getValue().split(":")[0])
- .anyMatch(slaveId -> slaveId.equals(extImpAdocean.getSlaveId()));
- if (isExistingSlaveId) {
- continue;
- }
-
- queryParams.add(new BasicNameValuePair("aid", extImpAdocean.getSlaveId() + ":" + impid));
- final List sizeValues = setSlaveSizesParam(slaveSizes, Objects.equals(test, 1));
- if (CollectionUtils.isNotEmpty(sizeValues)) {
- queryParams.add(new BasicNameValuePair("aosspsizes", String.join("-", sizeValues)));
- }
- uriBuilder.setParameters(queryParams);
-
- final String url = uriBuilder.toString();
- if (url.length() < MAX_URI_LENGTH) {
- final HttpRequest updatedRequest = HttpRequest.builder()
- .method(HttpMethod.GET)
- .uri(url)
- .headers(request.getHeaders())
- .build();
- httpRequests.remove(request);
- httpRequests.add(updatedRequest);
- return true;
- }
- }
- } catch (URISyntaxException e) {
- throw new PreBidException(e.getMessage());
- }
- }
- return false;
- }
-
- private String getImpSizes(Imp imp) {
- final Banner banner = imp.getBanner();
- if (banner == null) {
- return "";
- }
-
- final List format = banner.getFormat();
- if (CollectionUtils.isNotEmpty(format)) {
- final List sizes = new ArrayList<>();
- format.forEach(singleFormat -> sizes.add(
- "%sx%s".formatted(getIntOrElseZero(singleFormat.getW()), getIntOrElseZero(singleFormat.getH()))));
- return String.join("_", sizes);
- }
-
- final Integer w = banner.getW();
- final Integer h = banner.getH();
- if (w != null && h != null) {
- return "%sx%s".formatted(w, h);
- }
-
- return StringUtils.EMPTY;
- }
-
- private int getIntOrElseZero(Integer number) {
- return number != null ? number : 0;
- }
-
- private HttpRequest createSingleRequest(BidRequest request, Imp imp, ExtImpAdocean extImpAdocean,
- String consentString, Map slaveSizes) {
-
- return HttpRequest.builder()
- .method(HttpMethod.GET)
- .uri(buildUrl(imp.getId(), extImpAdocean, consentString, request, slaveSizes))
- .headers(getHeaders(request))
- .build();
- }
-
- private String buildUrl(String impId, ExtImpAdocean extImpAdocean, String consentString, BidRequest bidRequest,
- Map slaveSizes) {
-
- final Integer test = bidRequest.getTest();
- final String resolvedUrl = resolveEndpointUrl(extImpAdocean, test);
-
- final URIBuilder uriBuilder;
- try {
- uriBuilder = new URIBuilder(resolvedUrl);
- } catch (URISyntaxException e) {
- throw new PreBidException("Invalid url: %s, error: %s".formatted(resolvedUrl, e.getMessage()));
- }
-
- uriBuilder
- .addParameter("pbsrv_v", VERSION)
- .addParameter("id", extImpAdocean.getMasterId())
- .addParameter("nc", "1")
- .addParameter("nosecure", "1")
- .addParameter("aid", extImpAdocean.getSlaveId() + ":" + impId);
-
- if (StringUtils.isNotEmpty(consentString)) {
- uriBuilder.addParameter("gdpr_consent", consentString);
- uriBuilder.addParameter("gdpr", "1");
- }
-
- final User user = bidRequest.getUser();
- if (user != null && StringUtils.isNotEmpty(user.getBuyeruid())) {
- uriBuilder.addParameter("hcuserid", user.getBuyeruid());
- }
-
- final App app = bidRequest.getApp();
- if (app != null) {
- uriBuilder.addParameter("app", "1");
- uriBuilder.addParameter("appname", app.getName());
- uriBuilder.addParameter("appbundle", app.getBundle());
- uriBuilder.addParameter("appdomain", app.getDomain());
- }
-
- final Device device = bidRequest.getDevice();
- if (device != null) {
- if (StringUtils.isNotEmpty(device.getIfa())) {
- uriBuilder.addParameter("ifa", device.getIfa());
- } else {
- uriBuilder.addParameter("dpidmd5", device.getDpidmd5());
- }
-
- uriBuilder.addParameter("devos", device.getOs());
- uriBuilder.addParameter("devosv", device.getOsv());
- uriBuilder.addParameter("devmodel", device.getModel());
- uriBuilder.addParameter("devmake", device.getMake());
- }
-
- final List sizeValues = setSlaveSizesParam(slaveSizes, Objects.equals(test, 1));
-
- if (CollectionUtils.isNotEmpty(sizeValues)) {
- uriBuilder.addParameter("aosspsizes", String.join("-", sizeValues));
- }
-
- return uriBuilder.toString();
- }
-
- private String resolveEndpointUrl(ExtImpAdocean extImpAdocean, Integer test) {
- final String url = endpointUrl.replace("{{Host}}", extImpAdocean.getEmitterPrefix());
- final int randomizedPart = Objects.equals(test, 1) ? 10000000 : 10000000 + (int) (Math.random() * 89999999);
- return "%s/_%s/ad.json".formatted(url, randomizedPart);
- }
-
- private List setSlaveSizesParam(Map slaveSizes, boolean orderByKey) {
- final Set slaveIDs = orderByKey ? new TreeSet<>(slaveSizes.keySet()) : slaveSizes.keySet();
-
- return slaveIDs.stream()
- .filter(slaveId -> StringUtils.isNotEmpty(slaveSizes.get(slaveId)))
- .map(rawSlaveID -> "%s~%s".formatted(
- rawSlaveID.replaceFirst("adocean", ""),
- slaveSizes.get(rawSlaveID)))
- .toList();
- }
-
- private static MultiMap getHeaders(BidRequest request) {
- final MultiMap headers = HttpUtil.headers();
-
- final Device device = request.getDevice();
- if (device != null) {
- HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.USER_AGENT_HEADER, device.getUa());
- HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIpv6());
- HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIp());
- }
-
- final Site site = request.getSite();
- if (site != null) {
- HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.REFERER_HEADER, site.getPage());
- }
-
- return headers;
- }
-
- @Override
- public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) {
- final List params;
- try {
- params = URLEncodedUtils.parse(new URI(httpCall.getRequest().getUri()), StandardCharsets.UTF_8);
- } catch (URISyntaxException e) {
- return Result.withError(BidderError.badInput(e.getMessage()));
- }
-
- final Map auctionIds = params != null ? params.stream()
- .filter(param -> "aid".equals(param.getName()))
- .map(param -> param.getValue().split(":"))
- .collect(Collectors.toMap(name -> name[0], value -> value[1])) : null;
-
- final List adoceanResponses;
- try {
- adoceanResponses = getAdoceanResponseAdUnitList(httpCall.getResponse().getBody());
- } catch (PreBidException e) {
- return Result.withError(BidderError
- .badServerResponse("Failed to decode: No content to map due to end-of-input"));
- }
-
- final List bidderBids = adoceanResponses.stream()
- .filter(adoceanResponse -> !"true".equals(adoceanResponse.getError()))
- .filter(adoceanResponse ->
- StringUtils.isNotBlank(MapUtils.getString(auctionIds, adoceanResponse.getId())))
- .map(adoceanResponse -> BidderBid.of(createBid(auctionIds, adoceanResponse), BidType.banner,
- adoceanResponse.getCurrency()))
- .toList();
-
- return Result.withValues(bidderBids);
- }
-
- private static Bid createBid(Map auctionIds, AdoceanResponseAdUnit adoceanResponse) {
- final String adm = MEASUREMENT_CODE_TEMPLATE
- .formatted(adoceanResponse.getWinUrl(), adoceanResponse.getStatsUrl())
- + HttpUtil.decodeUrl(adoceanResponse.getCode());
- final String bidPrice = adoceanResponse.getPrice();
-
- return Bid.builder()
- .id(adoceanResponse.getId())
- .impid(auctionIds.get(adoceanResponse.getId()))
- .adm(adm)
- .price(NumberUtils.isParsable(bidPrice) ? new BigDecimal(bidPrice) : BigDecimal.ZERO)
- .w(NumberUtils.toInt(adoceanResponse.getWidth(), 0))
- .h(NumberUtils.toInt(adoceanResponse.getHeight(), 0))
- .crid(adoceanResponse.getCrid())
- .build();
- }
-
- private List getAdoceanResponseAdUnitList(String responseBody) {
- try {
- return mapper.mapper().readValue(
- responseBody,
- mapper.mapper().getTypeFactory().constructCollectionType(List.class, AdoceanResponseAdUnit.class));
- } catch (IOException e) {
- throw new PreBidException(e.getMessage());
- }
- }
-}
diff --git a/src/main/java/org/prebid/server/bidder/adocean/model/AdoceanResponseAdUnit.java b/src/main/java/org/prebid/server/bidder/adocean/model/AdoceanResponseAdUnit.java
deleted file mode 100644
index b2bd0142cee..00000000000
--- a/src/main/java/org/prebid/server/bidder/adocean/model/AdoceanResponseAdUnit.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.prebid.server.bidder.adocean.model;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Value;
-
-@Builder
-@Value
-public class AdoceanResponseAdUnit {
-
- String id;
-
- String crid;
-
- String currency;
-
- String price;
-
- String width;
-
- String height;
-
- String code;
-
- @JsonProperty("winurl")
- String winUrl;
-
- @JsonProperty("statsUrl")
- String statsUrl;
-
- String error;
-}
diff --git a/src/main/java/org/prebid/server/bidder/clydo/ClydoBidder.java b/src/main/java/org/prebid/server/bidder/clydo/ClydoBidder.java
new file mode 100644
index 00000000000..ca7b04ee32f
--- /dev/null
+++ b/src/main/java/org/prebid/server/bidder/clydo/ClydoBidder.java
@@ -0,0 +1,182 @@
+package org.prebid.server.bidder.clydo;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.iab.openrtb.request.BidRequest;
+import com.iab.openrtb.request.Device;
+import com.iab.openrtb.request.Imp;
+import com.iab.openrtb.response.Bid;
+import com.iab.openrtb.response.BidResponse;
+import com.iab.openrtb.response.SeatBid;
+import io.netty.handler.codec.http.HttpHeaderValues;
+import io.vertx.core.MultiMap;
+import org.prebid.server.bidder.Bidder;
+import org.prebid.server.bidder.model.BidderBid;
+import org.prebid.server.bidder.model.BidderCall;
+import org.prebid.server.bidder.model.BidderError;
+import org.prebid.server.bidder.model.HttpRequest;
+import org.prebid.server.bidder.model.Result;
+import org.prebid.server.exception.PreBidException;
+import org.prebid.server.json.DecodeException;
+import org.prebid.server.json.JacksonMapper;
+import org.prebid.server.proto.openrtb.ext.ExtPrebid;
+import org.prebid.server.proto.openrtb.ext.request.clydo.ExtImpClydo;
+import org.prebid.server.proto.openrtb.ext.response.BidType;
+import org.prebid.server.util.BidderUtil;
+import org.prebid.server.util.HttpUtil;
+import org.prebid.server.util.ObjectUtil;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class ClydoBidder implements Bidder {
+
+ private static final TypeReference> CLYDO_EXT_TYPE_REFERENCE =
+ new TypeReference<>() {
+ };
+
+ private static final String REGION_MACRO = "{{Region}}";
+ private static final String PARTNER_ID_MACRO = "{{PartnerId}}";
+ private static final String DEFAULT_REGION = "us";
+ private static final String X_OPENRTB_VERSION = "2.5";
+
+ private final String endpointUrl;
+ private final JacksonMapper mapper;
+
+ public ClydoBidder(String endpointUrl, JacksonMapper mapper) {
+ this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
+ this.mapper = Objects.requireNonNull(mapper);
+ }
+
+ @Override
+ public Result>> makeHttpRequests(BidRequest request) {
+ final List errors = new ArrayList<>();
+ final List> httpRequests = new ArrayList<>();
+
+ for (Imp imp : request.getImp()) {
+ try {
+ final ExtImpClydo extImpClydo = parseExtImp(imp);
+ final HttpRequest httpRequest = makeHttpRequest(request, imp, extImpClydo);
+ httpRequests.add(httpRequest);
+ } catch (PreBidException e) {
+ errors.add(BidderError.badInput(e.getMessage()));
+ }
+ }
+
+ if (httpRequests.isEmpty()) {
+ return Result.withError(BidderError.badInput("found no valid impressions"));
+ }
+
+ return Result.of(httpRequests, errors);
+ }
+
+ private ExtImpClydo parseExtImp(Imp imp) {
+ try {
+ return mapper.mapper().convertValue(imp.getExt(), CLYDO_EXT_TYPE_REFERENCE).getBidder();
+ } catch (IllegalArgumentException e) {
+ throw new PreBidException("Cannot deserialize ExtImpClydo: " + e.getMessage());
+ }
+ }
+
+ private HttpRequest makeHttpRequest(BidRequest request, Imp imp, ExtImpClydo extImpClydo) {
+ final BidRequest outgoingRequest = request.toBuilder().imp(List.of(imp)).build();
+
+ return BidderUtil.defaultRequest(
+ outgoingRequest,
+ constructHeaders(request),
+ resolveUrl(endpointUrl, extImpClydo), mapper);
+ }
+
+ private static MultiMap constructHeaders(BidRequest bidRequest) {
+ final Device device = bidRequest.getDevice();
+ final MultiMap headers = HttpUtil.headers();
+
+ headers.set(HttpUtil.X_OPENRTB_VERSION_HEADER, X_OPENRTB_VERSION);
+ headers.set(HttpUtil.ACCEPT_HEADER, HttpHeaderValues.APPLICATION_JSON);
+ headers.set(HttpUtil.CONTENT_TYPE_HEADER, HttpUtil.APPLICATION_JSON_CONTENT_TYPE);
+ HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER,
+ ObjectUtil.getIfNotNull(device, Device::getIpv6));
+ HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER,
+ ObjectUtil.getIfNotNull(device, Device::getIp));
+ HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.USER_AGENT_HEADER,
+ ObjectUtil.getIfNotNull(device, Device::getUa));
+
+ return headers;
+ }
+
+ private static String resolveUrl(String endpoint, ExtImpClydo extImp) {
+ return endpoint
+ .replace(REGION_MACRO, getRegionInfo(extImp))
+ .replace(PARTNER_ID_MACRO, HttpUtil.encodeUrl(extImp.getPartnerId()));
+ }
+
+ private static String getRegionInfo(ExtImpClydo extImp) {
+ final String region = extImp.getRegion();
+
+ return switch (region) {
+ case "us", "usw", "eu", "apac" -> region;
+ case null, default -> DEFAULT_REGION;
+ };
+ }
+
+ @Override
+ public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) {
+ try {
+ final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
+ final List bidderBids = extractBids(bidRequest, bidResponse);
+ return Result.withValues(bidderBids);
+ } catch (DecodeException | PreBidException e) {
+ return Result.withError(BidderError.badServerResponse(e.getMessage()));
+ }
+ }
+
+ private List extractBids(BidRequest bidRequest, BidResponse bidResponse) {
+ if (bidResponse == null || bidResponse.getSeatbid() == null || bidResponse.getSeatbid().isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ final Map impIdToBidTypeMap = buildImpIdToBidTypeMap(bidRequest);
+
+ return bidResponse.getSeatbid().stream()
+ .filter(Objects::nonNull)
+ .map(SeatBid::getBid)
+ .filter(Objects::nonNull)
+ .flatMap(List::stream)
+ .filter(Objects::nonNull)
+ .map(bid -> BidderBid.of(bid, resolveBidType(bid, impIdToBidTypeMap), bidResponse.getCur()))
+ .collect(Collectors.toList());
+ }
+
+ private static Map buildImpIdToBidTypeMap(BidRequest bidRequest) {
+ final Map impIdToBidTypeMap = new HashMap<>();
+ for (Imp imp : bidRequest.getImp()) {
+ final String impId = imp.getId();
+ final BidType bidType = determineBidType(imp);
+ impIdToBidTypeMap.put(impId, bidType);
+ }
+
+ return impIdToBidTypeMap;
+ }
+
+ private static BidType determineBidType(Imp imp) {
+ if (imp.getAudio() != null) {
+ return BidType.audio;
+ } else if (imp.getVideo() != null) {
+ return BidType.video;
+ } else if (imp.getXNative() != null) {
+ return BidType.xNative;
+ } else if (imp.getBanner() != null) {
+ return BidType.banner;
+ }
+
+ throw new PreBidException("Failed to get media type");
+ }
+
+ private static BidType resolveBidType(Bid bid, Map impIdToBidTypeMap) {
+ return impIdToBidTypeMap.getOrDefault(bid.getImpid(), BidType.banner);
+ }
+}
diff --git a/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java b/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java
index 180f545bf47..b4b643cc3eb 100644
--- a/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java
+++ b/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java
@@ -1,6 +1,7 @@
package org.prebid.server.bidder.nexx360;
import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Imp;
import com.iab.openrtb.response.Bid;
@@ -81,7 +82,9 @@ private ExtImpNexx360 parseImpExt(Imp imp) {
private Imp modifyImp(Imp imp) {
return imp.toBuilder()
- .ext(mapper.mapper().createObjectNode().set(BIDDER_NAME, imp.getExt().get("bidder")))
+ .ext(imp.getExt().deepCopy()
+ .without("bidder")
+ .set(BIDDER_NAME, imp.getExt().get("bidder")))
.build();
}
diff --git a/src/main/java/org/prebid/server/bidder/teal/TealBidder.java b/src/main/java/org/prebid/server/bidder/teal/TealBidder.java
new file mode 100644
index 00000000000..c1869421dd8
--- /dev/null
+++ b/src/main/java/org/prebid/server/bidder/teal/TealBidder.java
@@ -0,0 +1,200 @@
+package org.prebid.server.bidder.teal;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.iab.openrtb.request.App;
+import com.iab.openrtb.request.BidRequest;
+import com.iab.openrtb.request.Imp;
+import com.iab.openrtb.request.Publisher;
+import com.iab.openrtb.request.Site;
+import com.iab.openrtb.response.BidResponse;
+import com.iab.openrtb.response.SeatBid;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.prebid.server.bidder.Bidder;
+import org.prebid.server.bidder.model.BidderBid;
+import org.prebid.server.bidder.model.BidderCall;
+import org.prebid.server.bidder.model.BidderError;
+import org.prebid.server.bidder.model.HttpRequest;
+import org.prebid.server.bidder.model.Result;
+import org.prebid.server.exception.PreBidException;
+import org.prebid.server.json.DecodeException;
+import org.prebid.server.json.JacksonMapper;
+import org.prebid.server.proto.openrtb.ext.ExtPrebid;
+import org.prebid.server.proto.openrtb.ext.request.ExtRequest;
+import org.prebid.server.proto.openrtb.ext.request.teal.ExtImpTeal;
+import org.prebid.server.proto.openrtb.ext.response.BidType;
+import org.prebid.server.util.BidderUtil;
+import org.prebid.server.util.HttpUtil;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+public class TealBidder implements Bidder {
+
+ private static final TypeReference> TYPE_REFERENCE = new TypeReference<>() {
+ };
+
+ private final String endpointUrl;
+ private final JacksonMapper mapper;
+
+ public TealBidder(String endpointUrl, JacksonMapper mapper) {
+ this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
+ this.mapper = Objects.requireNonNull(mapper);
+ }
+
+ @Override
+ public Result>> makeHttpRequests(BidRequest request) {
+ final List modifiedImps = new ArrayList<>();
+ final List errors = new ArrayList<>();
+ String account = null;
+
+ for (Imp imp : request.getImp()) {
+ final ExtImpTeal extImpTeal;
+ try {
+ extImpTeal = parseImpExt(imp);
+ validateImpExt(extImpTeal);
+ } catch (PreBidException e) {
+ errors.add(BidderError.badInput(e.getMessage()));
+ continue;
+ }
+
+ account = account == null ? extImpTeal.getAccount() : account;
+ modifiedImps.add(modifyImp(imp, extImpTeal.getPlacement()));
+ }
+
+ if (modifiedImps.isEmpty()) {
+ return Result.withErrors(errors);
+ }
+
+ final BidRequest modifiedRequest = modifyBidRequest(request, account, modifiedImps);
+ return Result.of(
+ Collections.singletonList(BidderUtil.defaultRequest(modifiedRequest, endpointUrl, mapper)),
+ errors);
+ }
+
+ private ExtImpTeal parseImpExt(Imp imp) {
+ try {
+ return mapper.mapper().convertValue(imp.getExt(), TYPE_REFERENCE).getBidder();
+ } catch (IllegalArgumentException e) {
+ throw new PreBidException("Error parsing imp.ext for impression " + imp.getId());
+ }
+ }
+
+ private static void validateImpExt(ExtImpTeal extImpTeal) {
+ if (StringUtils.isBlank(extImpTeal.getAccount())) {
+ throw new PreBidException("account parameter failed validation");
+ }
+
+ final String placement = extImpTeal.getPlacement();
+ if (placement != null && StringUtils.isBlank(placement)) {
+ throw new PreBidException("placement parameter failed validation");
+ }
+ }
+
+ private static Imp modifyImp(Imp imp, String placement) {
+ if (placement == null) {
+ return imp;
+ }
+
+ final ObjectNode modifiedExt = imp.getExt().deepCopy();
+ getOrCreate(getOrCreate(modifiedExt, "prebid"), "storedrequest")
+ .put("id", placement);
+
+ return imp.toBuilder().ext(modifiedExt).build();
+ }
+
+ private static ObjectNode getOrCreate(ObjectNode parent, String field) {
+ final JsonNode child = parent.get(field);
+ return child != null && child.isObject()
+ ? (ObjectNode) child
+ : parent.putObject(field);
+ }
+
+ private BidRequest modifyBidRequest(BidRequest request, String account, List modifiedImps) {
+ final ExtRequest ext = ObjectUtils.defaultIfNull(request.getExt(), ExtRequest.empty());
+ ext.addProperty("bids", mapper.mapper().createObjectNode().put("pbs", 1));
+
+ return request.toBuilder()
+ .site(modifySite(request.getSite(), account))
+ .app(modifyApp(request.getApp(), account))
+ .imp(modifiedImps)
+ .ext(ext)
+ .build();
+ }
+
+ private static Site modifySite(Site site, String account) {
+ return site != null
+ ? site.toBuilder()
+ .publisher(modifyPublisher(site.getPublisher(), account))
+ .build()
+ : null;
+ }
+
+ private static App modifyApp(App app, String account) {
+ return app != null
+ ? app.toBuilder()
+ .publisher(modifyPublisher(app.getPublisher(), account))
+ .build()
+ : null;
+ }
+
+ private static Publisher modifyPublisher(Publisher publisher, String account) {
+ return Optional.ofNullable(publisher)
+ .map(Publisher::toBuilder)
+ .orElseGet(Publisher::builder)
+ .id(account)
+ .build();
+ }
+
+ @Override
+ public final Result> makeBids(BidderCall httpCall, BidRequest bidRequest) {
+ try {
+ final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
+ return Result.withValues(extractBids(httpCall.getRequest().getPayload(), bidResponse));
+ } catch (DecodeException e) {
+ return Result.withError(BidderError.badServerResponse(e.getMessage()));
+ }
+ }
+
+ private static List extractBids(BidRequest bidRequest, BidResponse bidResponse) {
+ if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) {
+ return Collections.emptyList();
+ }
+ return bidsFromResponse(bidRequest, bidResponse);
+ }
+
+ private static List bidsFromResponse(BidRequest bidRequest, BidResponse bidResponse) {
+ return bidResponse.getSeatbid().stream()
+ .filter(Objects::nonNull)
+ .map(SeatBid::getBid)
+ .filter(Objects::nonNull)
+ .flatMap(Collection::stream)
+ .filter(Objects::nonNull)
+ .map(bid -> BidderBid.of(bid, getBidType(bid.getImpid(), bidRequest.getImp()), bidResponse.getCur()))
+ .toList();
+ }
+
+ private static BidType getBidType(String impId, List imps) {
+ for (Imp imp : imps) {
+ if (imp.getId().equals(impId)) {
+ if (imp.getBanner() != null) {
+ return BidType.banner;
+ } else if (imp.getVideo() != null) {
+ return BidType.video;
+ } else if (imp.getAudio() != null) {
+ return BidType.audio;
+ } else if (imp.getXNative() != null) {
+ return BidType.xNative;
+ }
+ }
+ }
+ return BidType.banner;
+ }
+}
diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adocean/ExtImpAdocean.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adocean/ExtImpAdocean.java
deleted file mode 100644
index aa364d222ae..00000000000
--- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adocean/ExtImpAdocean.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.prebid.server.proto.openrtb.ext.request.adocean;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Value;
-
-/**
- * Defines the contract for bidrequest.imp[i].ext.adocean
- */
-@Value(staticConstructor = "of")
-public class ExtImpAdocean {
-
- @JsonProperty("emitterPrefix")
- String emitterPrefix;
-
- @JsonProperty("masterId")
- String masterId;
-
- @JsonProperty("slaveId")
- String slaveId;
-}
diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/clydo/ExtImpClydo.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/clydo/ExtImpClydo.java
new file mode 100644
index 00000000000..68338055de4
--- /dev/null
+++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/clydo/ExtImpClydo.java
@@ -0,0 +1,13 @@
+package org.prebid.server.proto.openrtb.ext.request.clydo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Value;
+
+@Value(staticConstructor = "of")
+public class ExtImpClydo {
+
+ @JsonProperty("partnerId")
+ String partnerId;
+
+ String region;
+}
diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/teal/ExtImpTeal.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/teal/ExtImpTeal.java
new file mode 100644
index 00000000000..e52ec990e84
--- /dev/null
+++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/teal/ExtImpTeal.java
@@ -0,0 +1,11 @@
+package org.prebid.server.proto.openrtb.ext.request.teal;
+
+import lombok.Value;
+
+@Value(staticConstructor = "of")
+public class ExtImpTeal {
+
+ String account;
+
+ String placement;
+}
diff --git a/src/main/java/org/prebid/server/spring/config/bidder/AdoceanConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/ClydoConfiguration.java
similarity index 59%
rename from src/main/java/org/prebid/server/spring/config/bidder/AdoceanConfiguration.java
rename to src/main/java/org/prebid/server/spring/config/bidder/ClydoConfiguration.java
index d16984e3c5e..98cedfc8d08 100644
--- a/src/main/java/org/prebid/server/spring/config/bidder/AdoceanConfiguration.java
+++ b/src/main/java/org/prebid/server/spring/config/bidder/ClydoConfiguration.java
@@ -1,7 +1,7 @@
package org.prebid.server.spring.config.bidder;
import org.prebid.server.bidder.BidderDeps;
-import org.prebid.server.bidder.adocean.AdoceanBidder;
+import org.prebid.server.bidder.clydo.ClydoBidder;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties;
import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler;
@@ -16,26 +16,26 @@
import jakarta.validation.constraints.NotBlank;
@Configuration
-@PropertySource(value = "classpath:/bidder-config/adocean.yaml", factory = YamlPropertySourceFactory.class)
-public class AdoceanConfiguration {
+@PropertySource(value = "classpath:/bidder-config/clydo.yaml", factory = YamlPropertySourceFactory.class)
+public class ClydoConfiguration {
- private static final String BIDDER_NAME = "adocean";
+ private static final String BIDDER_NAME = "clydo";
- @Bean("adoceanConfigurationProperties")
- @ConfigurationProperties("adapters.adocean")
+ @Bean("clydoConfigurationProperties")
+ @ConfigurationProperties("adapters.clydo")
BidderConfigurationProperties configurationProperties() {
return new BidderConfigurationProperties();
}
@Bean
- BidderDeps adoceanBidderDeps(BidderConfigurationProperties adoceanConfigurationProperties,
- @NotBlank @Value("${external-url}") String externalUrl,
- JacksonMapper mapper) {
+ BidderDeps clydoBidderDeps(BidderConfigurationProperties clydoConfigurationProperties,
+ @NotBlank @Value("${external-url}") String externalUrl,
+ JacksonMapper mapper) {
return BidderDepsAssembler.forBidder(BIDDER_NAME)
- .withConfig(adoceanConfigurationProperties)
+ .withConfig(clydoConfigurationProperties)
.usersyncerCreator(UsersyncerCreator.create(externalUrl))
- .bidderCreator(config -> new AdoceanBidder(config.getEndpoint(), mapper))
+ .bidderCreator(config -> new ClydoBidder(config.getEndpoint(), mapper))
.assemble();
}
}
diff --git a/src/main/java/org/prebid/server/spring/config/bidder/TealConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/TealConfiguration.java
new file mode 100644
index 00000000000..cbbff678a7e
--- /dev/null
+++ b/src/main/java/org/prebid/server/spring/config/bidder/TealConfiguration.java
@@ -0,0 +1,42 @@
+package org.prebid.server.spring.config.bidder;
+
+import org.prebid.server.bidder.BidderDeps;
+import org.prebid.server.bidder.teal.TealBidder;
+import org.prebid.server.json.JacksonMapper;
+import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties;
+import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler;
+import org.prebid.server.spring.config.bidder.util.UsersyncerCreator;
+import org.prebid.server.spring.env.YamlPropertySourceFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+import jakarta.validation.constraints.NotBlank;
+
+@Configuration
+@PropertySource(value = "classpath:/bidder-config/teal.yaml", factory = YamlPropertySourceFactory.class)
+public class TealConfiguration {
+
+ private static final String BIDDER_NAME = "teal";
+
+ @Bean("tealConfigurationProperties")
+ @ConfigurationProperties("adapters.teal")
+ BidderConfigurationProperties configurationProperties() {
+ return new BidderConfigurationProperties();
+ }
+
+ @Bean
+ BidderDeps tealBidderDeps(BidderConfigurationProperties tealConfigurationProperties,
+ @NotBlank @Value("${external-url}") String externalUrl,
+ JacksonMapper mapper) {
+
+ return BidderDepsAssembler.forBidder(BIDDER_NAME)
+ .withConfig(tealConfigurationProperties)
+ .usersyncerCreator(UsersyncerCreator.create(externalUrl))
+ .bidderCreator(config -> new TealBidder(config.getEndpoint(), mapper))
+ .assemble();
+ }
+
+}
diff --git a/src/main/resources/bidder-config/adocean.yaml b/src/main/resources/bidder-config/adocean.yaml
deleted file mode 100644
index f659947c985..00000000000
--- a/src/main/resources/bidder-config/adocean.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-adapters:
- adocean:
- endpoint: https://{{Host}}.adocean.pl
- meta-info:
- maintainer-email: aoteam@gemius.com
- app-media-types:
- - banner
- site-media-types:
- - banner
- supported-vendors:
- vendor-id: 328
diff --git a/src/main/resources/bidder-config/adverxo.yaml b/src/main/resources/bidder-config/adverxo.yaml
index d2fd18f505b..b363a70bc08 100644
--- a/src/main/resources/bidder-config/adverxo.yaml
+++ b/src/main/resources/bidder-config/adverxo.yaml
@@ -31,20 +31,6 @@ adapters:
url: https://taetee.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
uid-macro: '$UID'
support-cors: false
- mobupps:
- enabled: false
- endpoint: https://mobupps.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}}
- usersync:
- enabled: false
- cookie-family-name: mobupps
- iframe:
- url: https://mobupps.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
- uid-macro: '$UID'
- support-cors: false
- redirect:
- url: https://mobupps.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
- uid-macro: '$UID'
- support-cors: false
meta-info:
maintainer-email: developer@adverxo.com
app-media-types:
diff --git a/src/main/resources/bidder-config/aso.yaml b/src/main/resources/bidder-config/aso.yaml
index fa6a6381741..5f3bdad4829 100644
--- a/src/main/resources/bidder-config/aso.yaml
+++ b/src/main/resources/bidder-config/aso.yaml
@@ -7,16 +7,34 @@ adapters:
endpoint: https://srv.datacygnal.io/pbs/bidder?zid={{ZoneID}}
meta-info:
maintainer-email: contact@bcm.ltd
+ usersync:
+ cookie-family-name: bcmint
+ redirect:
+ url: https://track.datacygnal.io/sync/v2?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&usp={{us_privacy}}&gpp={{gpp}}&gpp_sid={{gpp_sid}}&redir={{redirect_url}}
+ support-cors: false
+ uid-macro: '{uid}'
bidagency:
enabled: false
endpoint: https://srv.bidgx.com/pbs/bidder?zid={{ZoneID}}
meta-info:
maintainer-email: aso@bidgency.com
+ usersync:
+ cookie-family-name: bidagency
+ redirect:
+ url: https://track.bidgx.com/sync/v2?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&usp={{us_privacy}}&gpp={{gpp}}&gpp_sid={{gpp_sid}}&redir={{redirect_url}}
+ support-cors: false
+ uid-macro: '{uid}'
kuantyx:
enabled: false
endpoint: https://srv.kntxy.com/pbs/bidder?zid={{ZoneID}}
meta-info:
maintainer-email: ssp@kuantyx.com
+ usersync:
+ cookie-family-name: kuantyx
+ redirect:
+ url: https://track.kntxy.com/sync/v2?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&usp={{us_privacy}}&gpp={{gpp}}&gpp_sid={{gpp_sid}}&redir={{redirect_url}}
+ support-cors: false
+ uid-macro: '{uid}'
meta-info:
maintainer-email: support@adsrv.org
app-media-types:
@@ -28,3 +46,9 @@ adapters:
- video
- native
vendor-id: 0
+ usersync:
+ cookie-family-name: aso
+ redirect:
+ url: https://track.aso1.net/sync/v2?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&usp={{us_privacy}}&gpp={{gpp}}&gpp_sid={{gpp_sid}}&redir={{redirect_url}}
+ support-cors: false
+ uid-macro: '{uid}'
diff --git a/src/main/resources/bidder-config/clydo.yaml b/src/main/resources/bidder-config/clydo.yaml
new file mode 100644
index 00000000000..aa90e3a4f07
--- /dev/null
+++ b/src/main/resources/bidder-config/clydo.yaml
@@ -0,0 +1,21 @@
+adapters:
+ clydo:
+ endpoint: http://region={{Region}}.clydo.io/partnerId={{PartnerId}}
+ modifying-vast-xml-allowed: true
+ endpoint-compression: gzip
+ geoscope:
+ - global
+ meta-info:
+ maintainer-email: cto@clydo.io
+ app-media-types:
+ - banner
+ - video
+ - audio
+ - native
+ site-media-types:
+ - banner
+ - video
+ - audio
+ - native
+ supported-vendors:
+ vendor-id: 0
diff --git a/src/main/resources/bidder-config/nexx360.yaml b/src/main/resources/bidder-config/nexx360.yaml
index 443ca7f5ab4..975dcd6a21e 100644
--- a/src/main/resources/bidder-config/nexx360.yaml
+++ b/src/main/resources/bidder-config/nexx360.yaml
@@ -19,4 +19,4 @@ adapters:
- native
- audio
supported-vendors:
- vendor-id: 0
+ vendor-id: 965
diff --git a/src/main/resources/bidder-config/smarthub.yaml b/src/main/resources/bidder-config/smarthub.yaml
index 73a50212676..e3d370266b5 100644
--- a/src/main/resources/bidder-config/smarthub.yaml
+++ b/src/main/resources/bidder-config/smarthub.yaml
@@ -11,9 +11,6 @@ adapters:
tredio:
enabled: false
endpoint: https://tredio-prebid.attekmi.com/pbserver/?seat={{AccountID}}&token={{SourceId}}
- vimayx:
- enabled: false
- endpoint: https://vimayx-prebid.attekmi.com/pbserver/?seat={{AccountID}}&token={{SourceId}}
felixads:
enabled: false
endpoint: https://felixads-prebid.attekmi.com/pbserver/?seat={{AccountID}}&token={{SourceId}}
@@ -29,6 +26,9 @@ adapters:
addigi:
enabled: false
endpoint: https://addigi-prebid.attekmi.com/pbserver/?seat={{AccountID}}&token={{SourceId}}
+ radianfusion:
+ enabled: false
+ endpoint: https://radiantfusion-prebid.attekmi.co/pbserver/?seat={{AccountID}}&token={{SourceId}}
meta-info:
maintainer-email: prebid@attekmi.com
app-media-types:
diff --git a/src/main/resources/bidder-config/teal.yaml b/src/main/resources/bidder-config/teal.yaml
new file mode 100644
index 00000000000..00d1a6d48fc
--- /dev/null
+++ b/src/main/resources/bidder-config/teal.yaml
@@ -0,0 +1,30 @@
+adapters:
+ teal:
+ ortb-version: "2.6"
+ endpoint: https://a.bids.ws/openrtb2/auction
+ modifying-vast-xml-allowed: true
+ endpoint-compression: gzip
+ geoscope:
+ - global
+ aliases:
+ tealplus:
+ enabled: false
+ ortb:
+ multiformat-supported: true
+ meta-info:
+ maintainer-email: prebid@teal.works
+ app-media-types:
+ - banner
+ - video
+ - native
+ site-media-types:
+ - banner
+ - video
+ - native
+ supported-vendors:
+ vendor-id: 1378
+ usersync:
+ cookie-family-name: teal
+ iframe:
+ url: https://bids.ws/load-pbs.html?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect_url={{redirect_url}}
+ support-cors: false
diff --git a/src/main/resources/bidder-config/teqblaze.yaml b/src/main/resources/bidder-config/teqblaze.yaml
index 5e1006433ae..a7647ad62f3 100644
--- a/src/main/resources/bidder-config/teqblaze.yaml
+++ b/src/main/resources/bidder-config/teqblaze.yaml
@@ -2,6 +2,21 @@ adapters:
teqblaze:
endpoint: http://
aliases:
+ 360playvid:
+ enabled: false
+ endpoint: https://ssp.360playvid.com/pserver
+ meta-info:
+ maintainer-email: prebid@360playvid.com
+ usersync:
+ enabled: true
+ redirect:
+ url: https://cookie.360playvid.com/pbserver?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&coppa={{us_privacy}}&gpp={{gpp}}&gpp_sid={{gpp_sid}}&redir={{redirect_url}}
+ support-cors: false
+ uid-macro: '[UID]'
+ iframe:
+ url: https://cookie.360playvid.com/pbserverIframe?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&ccpa={{us_privacy}}&gpp={{gpp}}&gpp_sid={{gpp_sid}}&pbserverUrl={{redirect_url}}
+ uid-macro: '[UID]'
+ support-cors: false
pinkLion:
enabled: false
endpoint: https://us-east-ep.pinklion.io/pserver
@@ -43,6 +58,23 @@ adapters:
mata-info:
maintainer-email: support@gravite.net
vendor-id: 377
+ progx:
+ enabled: false
+ endpoint: https://us-east.progrtb.com/pserver
+ meta-info:
+ maintainer-email: pxteam@programmaticx.ai
+ vendor-id: 1344
+ usersync:
+ enabled: true
+ cookie-family-name: progx
+ iframe:
+ url: https://sync.progrtb.com/pbserverIframe?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&ccpa={{us_privacy}}&gpp={{gpp}}&gpp_sid={{gpp_sid}}&pbserverUrl={{.RedirectURL}}
+ support-cors: false
+ uid-macro: '[UID]'
+ redirect:
+ url: https://sync.progrtb.com/pbserver?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&ccpa={{us_privacy}}&gpp={{gpp}}&gpp_sid={{gpp_sid}}&redir={{redirect_url}}
+ support-cors: false
+ uid-macro: '[UID]'
meta-info:
maintainer-email: github@teqblaze.com
app-media-types:
diff --git a/src/main/resources/bidder-config/vidazoo.yaml b/src/main/resources/bidder-config/vidazoo.yaml
index 3e1768fb0cb..adb9b9758a5 100644
--- a/src/main/resources/bidder-config/vidazoo.yaml
+++ b/src/main/resources/bidder-config/vidazoo.yaml
@@ -2,19 +2,6 @@ adapters:
vidazoo:
endpoint: https://prebidsrvr.cootlogix.com/openrtb/
aliases:
- progx:
- enabled: false
- endpoint: https://exchange.programmaticx.ai/openrtb/
- meta-info:
- maintainer-email: pxteam@programmaticx.ai
- vendor-id: 1344
- usersync:
- enabled: true
- cookie-family-name: progx
- iframe:
- url: https://sync.programmaticx.ai/api/user/html/685297194d85991a5e6e36dd?pbs=true&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}&gpp={{gpp}}&gpp_sid={{gpp_sid}}
- support-cors: false
- uid-macro: '${userId}'
omnidex:
endpoint: https://exchange.omni-dex.io/openrtb/
usersync:
diff --git a/src/main/resources/static/bidder-params/adocean.json b/src/main/resources/static/bidder-params/adocean.json
deleted file mode 100644
index 5c62c410fb1..00000000000
--- a/src/main/resources/static/bidder-params/adocean.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "title": "AdOcean Adapter Params",
- "description": "A schema which validates params accepted by the AdOcean adapter",
- "type": "object",
- "properties": {
- "emiter": {
- "type": "string",
- "description": "Deprecated, use emitterPrefix instead. AdOcean emiter",
- "pattern": ".+"
- },
- "emitterPrefix": {
- "type": "string",
- "description": "AdOcean emitter prefix",
- "pattern": "^[\\w\\-]+$"
- },
- "masterId": {
- "type": "string",
- "description": "Master's id",
- "pattern": "^[\\w.]+$"
- },
- "slaveId": {
- "type": "string",
- "description": "Slave's id",
- "pattern": "^adocean[\\w.]+$"
- }
- },
- "oneOf": [
- {
- "required": [
- "emiter",
- "masterId",
- "slaveId"
- ]
- },
- {
- "required": [
- "emitterPrefix",
- "masterId",
- "slaveId"
- ]
- }
- ]
-}
diff --git a/src/main/resources/static/bidder-params/adot.json b/src/main/resources/static/bidder-params/adot.json
index e82b17be8d4..45caca4da80 100644
--- a/src/main/resources/static/bidder-params/adot.json
+++ b/src/main/resources/static/bidder-params/adot.json
@@ -14,7 +14,8 @@
},
"publisherPath": {
"type": "string",
- "description": "An optional path used in the bid endpoint"
+ "enum": ["/hubvisor", "/spotx"],
+ "description": "An optional path used in the bid endpoint. Only '/hubvisor' and '/spotx' are allowed."
}
},
"required": []
diff --git a/src/main/resources/static/bidder-params/clydo.json b/src/main/resources/static/bidder-params/clydo.json
new file mode 100644
index 00000000000..71b60d09405
--- /dev/null
+++ b/src/main/resources/static/bidder-params/clydo.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Clydo Adapter Params",
+ "description": "A schema which validates params accepted by the Clydo adapter",
+ "type": "object",
+ "properties": {
+ "partnerId": {
+ "type": "string",
+ "description": "Partner ID",
+ "minLength": 1
+ },
+ "region": {
+ "type": "string",
+ "description": "Regional endpoint identifier (us, usw, eu, apac)",
+ "enum": ["us", "usw", "eu", "apac"]
+ }
+ },
+
+ "required": ["partnerId"]
+}
diff --git a/src/main/resources/static/bidder-params/teal.json b/src/main/resources/static/bidder-params/teal.json
new file mode 100644
index 00000000000..52e073c3af4
--- /dev/null
+++ b/src/main/resources/static/bidder-params/teal.json
@@ -0,0 +1,19 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Teal Adapter Params",
+ "description": "A schema which validates params accepted by the Teal adapter",
+ "type": "object",
+ "properties": {
+ "account": {
+ "type": "string",
+ "description": "Account ID"
+ },
+ "placement": {
+ "type": "string",
+ "description": "Placement ID or name (optional)"
+ }
+ },
+ "required": [
+ "account"
+ ]
+}
diff --git a/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java b/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java
deleted file mode 100644
index 9657dd88767..00000000000
--- a/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java
+++ /dev/null
@@ -1,572 +0,0 @@
-package org.prebid.server.bidder.adocean;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.iab.openrtb.request.App;
-import com.iab.openrtb.request.Banner;
-import com.iab.openrtb.request.BidRequest;
-import com.iab.openrtb.request.Device;
-import com.iab.openrtb.request.Format;
-import com.iab.openrtb.request.Imp;
-import com.iab.openrtb.request.Site;
-import com.iab.openrtb.request.User;
-import com.iab.openrtb.response.Bid;
-import io.netty.handler.codec.http.HttpHeaderValues;
-import org.junit.jupiter.api.Test;
-import org.prebid.server.VertxTest;
-import org.prebid.server.bidder.adocean.model.AdoceanResponseAdUnit;
-import org.prebid.server.bidder.model.BidderBid;
-import org.prebid.server.bidder.model.BidderCall;
-import org.prebid.server.bidder.model.BidderError;
-import org.prebid.server.bidder.model.HttpRequest;
-import org.prebid.server.bidder.model.HttpResponse;
-import org.prebid.server.bidder.model.Result;
-import org.prebid.server.proto.openrtb.ext.ExtPrebid;
-import org.prebid.server.proto.openrtb.ext.request.ExtUser;
-import org.prebid.server.proto.openrtb.ext.request.adocean.ExtImpAdocean;
-import org.prebid.server.proto.openrtb.ext.response.BidType;
-import org.prebid.server.util.HttpUtil;
-
-import java.math.BigDecimal;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonList;
-import static java.util.function.Function.identity;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.prebid.server.bidder.model.BidderError.Type.bad_server_response;
-
-public class AdoceanBidderTest extends VertxTest {
-
- private static final String ENDPOINT_URL = "https://{{Host}}";
-
- private final AdoceanBidder target = new AdoceanBidder(ENDPOINT_URL, jacksonMapper);
-
- @Test
- public void creationShouldFailOnInvalidEndpointUrl() {
- assertThatIllegalArgumentException().isThrownBy(() -> new AdoceanBidder("invalid_url", jacksonMapper));
- }
-
- @Test
- public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() {
- // given
- final BidRequest bidRequest = givenBidRequest(
- impBuilder -> impBuilder
- .id("123")
- .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))));
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getErrors())
- .containsExactly(BidderError.badInput("Error parsing adOceanExt parameters, in imp with id : 123"));
- }
-
- @Test
- public void makeHttpRequestsShouldReturnErrorIfEndpointUrlComposingFails() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(singletonList(Imp.builder()
- .id("ao-test")
- .banner(Banner.builder().build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("invalid domain", "masterId",
- "adoceanmyaozpniqismex")))).build()))
- .test(1)
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getErrors()).hasSize(1)
- .allSatisfy(error -> {
- assertThat(error.getMessage()).startsWith("Invalid url: https://invalid domain/");
- assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input);
- });
- }
-
- @Test
- public void makeHttpRequestsShouldReturnErrorIfExtImpEmitterPrefixIsEmpty() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(singletonList(Imp.builder()
- .id("ao-test")
- .banner(Banner.builder().build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("", "masterId", "adoceanmyaozpniqismex")))).build()))
- .test(1)
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getValue()).isEmpty();
- assertThat(result.getErrors()).containsExactly(BidderError.badInput("No emitterPrefix param"));
- }
-
- @Test
- public void makeHttpRequestsShouldReturnErrorIfExtImpEmitterPrefixIsNotSupplied() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(singletonList(Imp.builder()
- .id("ao-test")
- .banner(Banner.builder().build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of(null, "masterId", "adoceanmyaozpniqismex")))).build()))
- .test(1)
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getValue()).isEmpty();
- assertThat(result.getErrors()).containsExactly(BidderError.badInput("No emitterPrefix param"));
- }
-
- @Test
- public void makeHttpRequestsShouldCreateRequestForEveryValidImp() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .buyeruid("testBuyerUid")
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(asList(Imp.builder()
- .id("ao-test")
- .banner(Banner.builder().format(asList(Format.builder().h(250).w(300).build(),
- Format.builder().h(320).w(600).build())).build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl", "masterId",
- "adoceanmyaozpniqismex")))).build(),
- Imp.builder()
- .id("notValidImp")
- .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))).build(),
- Imp.builder()
- .id("i2-test")
- .banner(Banner.builder().w(577).h(333).build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("em.dom", "masterId2",
- "slaveId")))).build()))
- .test(1)
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getErrors())
- .containsExactly(BidderError.badInput("Error parsing adOceanExt parameters, "
- + "in imp with id : notValidImp"));
- assertThat(result.getValue()).hasSize(2)
- .extracting(HttpRequest::getUri)
- .containsExactly("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0&id=masterId&nc=1"
- + "&nosecure=1&aid=adoceanmyaozpniqismex%3Aao-test&gdpr_consent=consent&gdpr=1"
- + "&hcuserid=testBuyerUid&aosspsizes=myaozpniqismex"
- + "%7E300x250_600x320", "https://em.dom/_10000000/ad.json?pbsrv_v=1.3.0&id="
- + "masterId2&nc=1&nosecure=1&aid=slaveId%3Ai2-test&gdpr_consent=consent&gdpr=1"
- + "&hcuserid=testBuyerUid&aosspsizes=slaveId%7E577x333");
- }
-
- @Test
- public void makeHttpRequestsShouldCreateUniqueRequestIfMasterIdEqualsAndSlaveIdExists() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .buyeruid("testBuyerUid")
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(asList(Imp.builder()
- .id("ao-test")
- .banner(Banner.builder().format(asList(Format.builder().h(250).w(300).build(),
- Format.builder().h(320).w(600).build())).build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl", "masterId",
- "slaveId")))).build(),
- Imp.builder()
- .id("i2-test")
- .banner(Banner.builder().w(577).h(333).build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("em.dom", "masterId",
- "slaveId")))).build()))
- .test(1)
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getValue()).hasSize(2);
- }
-
- @Test
- public void makeHttpRequestsShouldCreateRequestWithoutSizeIfBannerSizesNotPresent() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(singletonList(Imp.builder()
- .id("ao-test")
- .banner(Banner.builder().build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl", "masterId",
- "adoceanmyaozpniqismex")))).build()))
- .test(1)
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getErrors()).isEmpty();
- assertThat(result.getValue())
- .extracting(HttpRequest::getUri)
- .containsExactly("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0&id=masterId&nc=1&nosecure=1"
- + "&aid=adoceanmyaozpniqismex%3Aao-test&gdpr_consent=consent&gdpr=1");
- }
-
- @Test
- public void makeHttpRequestsShouldUpdateRequestsForSimilarSlaveIds() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .buyeruid("testBuyerUid")
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(asList(Imp.builder()
- .id("ao-test")
- .banner(Banner.builder().format(asList(Format.builder().h(250).w(300).build(),
- Format.builder().h(320).w(600).build())).build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl", "masterId",
- "slaveId")))).build(),
- Imp.builder()
- .id("i2-test")
- .banner(Banner.builder().w(577).h(333).build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("em.dom", "masterId",
- "slaveId2")))).build()))
- .test(1)
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getValue()).hasSize(1)
- .extracting(HttpRequest::getUri)
- .containsExactlyInAnyOrder("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0&id=masterId&nc=1"
- + "&nosecure=1&aid=slaveId%3Aao-test&gdpr_consent=consent&gdpr=1&hcuserid=testBuyerUid"
- + "&aosspsizes=slaveId%7E300x250_600x320&aid=slaveId2%3Ai2-test&aosspsizes=slaveId2%7E577x333");
- }
-
- @Test
- public void makeHttpRequestsShouldSetExpectedHeadersIfDeviceIpIsPresent() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(singletonList(Imp.builder()
- .id("ao-test")
- .banner(Banner.builder().format(singletonList(Format.builder().w(300).h(250).build()))
- .id("banner_id").build())
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl",
- "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
- "adoceanmyaozpniqismex"))))
- .build()))
- .test(1)
- .device(Device.builder().ip("192.168.1.1").build())
- .site(Site.builder().page("http://www.example.com").build())
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getValue().getFirst().getHeaders()).isNotNull()
- .extracting(Map.Entry::getKey, Map.Entry::getValue)
- .containsExactly(tuple(HttpUtil.CONTENT_TYPE_HEADER.toString(), HttpUtil.APPLICATION_JSON_CONTENT_TYPE),
- tuple(HttpUtil.ACCEPT_HEADER.toString(), HttpHeaderValues.APPLICATION_JSON.toString()),
- tuple(HttpUtil.X_FORWARDED_FOR_HEADER.toString(), "192.168.1.1"),
- tuple(HttpUtil.REFERER_HEADER.toString(), "http://www.example.com"));
- }
-
- @Test
- public void makeHttpRequestsShouldSetExpectedHeadersIfDeviceIpv6IsPresent() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(singletonList(Imp.builder()
- .id("ao-test")
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl", "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
- "adoceanmyaozpniqismex"))))
- .build()))
- .test(1)
- .device(Device.builder().ipv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334").build())
- .site(Site.builder().page("http://www.example.com").build())
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getValue().getFirst().getHeaders()).isNotNull()
- .extracting(Map.Entry::getKey, Map.Entry::getValue)
- .containsExactly(tuple(HttpUtil.CONTENT_TYPE_HEADER.toString(), HttpUtil.APPLICATION_JSON_CONTENT_TYPE),
- tuple(HttpUtil.ACCEPT_HEADER.toString(), HttpHeaderValues.APPLICATION_JSON.toString()),
- tuple(HttpUtil.X_FORWARDED_FOR_HEADER.toString(), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
- tuple(HttpUtil.REFERER_HEADER.toString(), "http://www.example.com"));
- }
-
- @Test
- public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() throws JsonProcessingException {
- // given
- final BidderCall httpCall = givenHttpCall(null, "");
-
- // when
- final Result> result = target.makeBids(httpCall, null);
-
- // then
- assertThat(result.getErrors()).hasSize(1)
- .allSatisfy(error -> {
- assertThat(error.getType()).isEqualTo(bad_server_response);
- assertThat(error.getMessage())
- .startsWith("Failed to decode: No content to map due to end-of-input");
- });
- assertThat(result.getValue()).isEmpty();
- }
-
- @Test
- public void makeBidsShouldReturnCorrectBidderBid() throws JsonProcessingException {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .imp(singletonList(Imp.builder()
- .id("impId")
- .build()))
- .build();
- final List adoceanResponseAdUnit = asList(adoceanResponseCreator(identity()),
- adoceanResponseCreator(response -> response.id("adoceanmyaozpniqis")));
-
- final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(adoceanResponseAdUnit));
-
- // when
- final Result> result = target.makeBids(httpCall, bidRequest);
-
- // then
- final String adm = """
- \s""".formatted("https://win-url.com", "https://stats-url.com");
-
- final BidderBid expected = BidderBid.of(
- Bid.builder()
- .id("ad")
- .impid("ao-test")
- .adm(adm)
- .price(BigDecimal.valueOf(1))
- .crid("0af345b42983cc4bc0")
- .w(300)
- .h(250)
- .build(),
- BidType.banner, "EUR");
- assertThat(result.getValue().getFirst().getBid().getAdm()).isEqualTo(adm);
- assertThat(result.getErrors()).isEmpty();
- assertThat(result.getValue()).doesNotContainNull().hasSize(1).element(0).isEqualTo(expected);
- }
-
- @Test
- public void makeBidsShouldReturnEmptyListOfBids() throws JsonProcessingException {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .imp(singletonList(Imp.builder()
- .id("impId")
- .build()))
- .build();
- final List adoceanResponseAdUnit = asList(
- adoceanResponseCreator(response -> response.error("true")),
- adoceanResponseCreator(response -> response.id("adoceanmyaozpniqis")));
-
- final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(adoceanResponseAdUnit));
-
- // when
- final Result> result = target.makeBids(httpCall, bidRequest);
-
- // then
- assertThat(result.getErrors()).isEmpty();
- assertThat(result.getValue()).isEqualTo(Collections.emptyList());
- }
-
- @Test
- public void makeHttpRequestsShouldBuildUrlIfAppIsPresent() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(singletonList(Imp.builder()
- .id("ao-test")
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl", "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
- "adoceanmyaozpniqismex"))))
- .build()))
- .test(1)
- .app(App.builder().name("name").bundle("bundle").domain("domain").build())
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getValue()).hasSize(1)
- .extracting(HttpRequest::getUri)
- .containsExactlyInAnyOrder("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0"
- + "&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1"
- + "&aid=adoceanmyaozpniqismex%3Aao-test&gdpr_consent=consent"
- + "&gdpr=1&app=1&appname=name&appbundle=bundle&appdomain=domain");
- }
-
- @Test
- public void makeHttpRequestsShouldBuildUrlIfDeviceWithIfaIsPresent() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(singletonList(Imp.builder()
- .id("ao-test")
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl", "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
- "adoceanmyaozpniqismex"))))
- .build()))
- .test(1)
- .device(Device.builder().ifa("ifa").os("os").osv("osv").model("model").make("make").build())
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getValue()).hasSize(1)
- .extracting(HttpRequest::getUri)
- .containsExactlyInAnyOrder("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0"
- + "&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7"
- + "&nc=1&nosecure=1&aid=adoceanmyaozpniqismex%3Aao-test"
- + "&gdpr_consent=consent&gdpr=1&ifa=ifa&devos=os&devosv=osv&devmodel=model&devmake=make");
- }
-
- @Test
- public void makeHttpRequestsShouldBuildUrlIfDeviceWithIfaIsNotPresent() {
- // given
- final BidRequest bidRequest = BidRequest.builder()
- .user(User.builder()
- .ext(ExtUser.builder()
- .consent("consent").build())
- .build())
- .imp(singletonList(Imp.builder()
- .id("ao-test")
- .ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl", "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
- "adoceanmyaozpniqismex"))))
- .build()))
- .test(1)
- .device(Device.builder().dpidmd5("dpidmd5").os("os").osv("osv").model("model").make("make").build())
- .build();
-
- // when
- final Result>> result = target.makeHttpRequests(bidRequest);
-
- // then
- assertThat(result.getValue()).hasSize(1)
- .extracting(HttpRequest::getUri)
- .containsExactlyInAnyOrder("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0"
- + "&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7"
- + "&nc=1&nosecure=1&aid=adoceanmyaozpniqismex%3Aao-test"
- + "&gdpr_consent=consent&gdpr=1&dpidmd5=dpidmd5&devos=os&devosv=osv"
- + "&devmodel=model&devmake=make");
- }
-
- private static AdoceanResponseAdUnit adoceanResponseCreator(
- Function adoceanCustomizer) {
- return adoceanCustomizer.apply(AdoceanResponseAdUnit.builder()
- .id("ad")
- .price("1")
- .winUrl("https://win-url.com")
- .statsUrl("https://stats-url.com")
- .code(" ")
- .currency("EUR")
- .width("300")
- .height("250")
- .crid("0af345b42983cc4bc0")
- .error("false"))
- .build();
- }
-
- private static BidRequest givenBidRequest(
- Function bidRequestCustomizer,
- Function impCustomizer) {
-
- return bidRequestCustomizer.apply(BidRequest.builder()
- .imp(singletonList(givenImp(impCustomizer))))
- .build();
- }
-
- private static BidRequest givenBidRequest(Function impCustomizer) {
- return givenBidRequest(identity(), impCustomizer);
- }
-
- private static Imp givenImp(Function impCustomizer) {
- return impCustomizer.apply(Imp.builder()
- .id("123")
- .banner(Banner.builder().id("banner_id").build()).ext(mapper.valueToTree(ExtPrebid.of(null,
- ExtImpAdocean.of("myao.adocean.pl", "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
- "adoceanmyaozpniqismex")))))
- .build();
- }
-
- private static BidderCall givenHttpCall(String requestBody, String responseBody)
- throws JsonProcessingException {
- return BidderCall.succeededHttp(
- HttpRequest.builder()
- .body(mapper.writeValueAsBytes(requestBody))
- .uri("https://myao.adocean.pl/_10000000/ad.json?aid=ad%3Aao-test&gdpr=1&gdpr_consent=consent"
- + "&nc=1&nosecure=1&pbsrv_v=1.0.0")
- .build(),
- HttpResponse.of(200, null, responseBody), null);
- }
-}
diff --git a/src/test/java/org/prebid/server/bidder/clydo/ClydoBidderTest.java b/src/test/java/org/prebid/server/bidder/clydo/ClydoBidderTest.java
new file mode 100644
index 00000000000..d4fc86456f5
--- /dev/null
+++ b/src/test/java/org/prebid/server/bidder/clydo/ClydoBidderTest.java
@@ -0,0 +1,383 @@
+package org.prebid.server.bidder.clydo;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.iab.openrtb.request.Audio;
+import com.iab.openrtb.request.Banner;
+import com.iab.openrtb.request.BidRequest;
+import com.iab.openrtb.request.Imp;
+import com.iab.openrtb.request.Native;
+import com.iab.openrtb.request.Video;
+import com.iab.openrtb.response.Bid;
+import com.iab.openrtb.response.BidResponse;
+import com.iab.openrtb.response.SeatBid;
+import org.junit.jupiter.api.Test;
+import org.prebid.server.VertxTest;
+import org.prebid.server.bidder.model.BidderBid;
+import org.prebid.server.bidder.model.BidderCall;
+import org.prebid.server.bidder.model.BidderError;
+import org.prebid.server.bidder.model.HttpRequest;
+import org.prebid.server.bidder.model.HttpResponse;
+import org.prebid.server.bidder.model.Result;
+import org.prebid.server.proto.openrtb.ext.ExtPrebid;
+import org.prebid.server.proto.openrtb.ext.request.clydo.ExtImpClydo;
+
+import java.util.List;
+import java.util.function.UnaryOperator;
+
+import static java.util.Arrays.asList;
+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.prebid.server.proto.openrtb.ext.response.BidType.audio;
+import static org.prebid.server.proto.openrtb.ext.response.BidType.banner;
+import static org.prebid.server.proto.openrtb.ext.response.BidType.video;
+import static org.prebid.server.proto.openrtb.ext.response.BidType.xNative;
+import static org.prebid.server.util.HttpUtil.ACCEPT_HEADER;
+import static org.prebid.server.util.HttpUtil.APPLICATION_JSON_CONTENT_TYPE;
+import static org.prebid.server.util.HttpUtil.CONTENT_TYPE_HEADER;
+import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
+
+public class ClydoBidderTest extends VertxTest {
+
+ private static final String ENDPOINT_URL = "http://region={{Region}}.clydo.io/partnerId={{PartnerId}}";
+
+ private final ClydoBidder target = new ClydoBidder(ENDPOINT_URL, jacksonMapper);
+
+ @Test
+ public void creationShouldFailOnInvalidEndpointUrl() {
+ assertThatIllegalArgumentException().isThrownBy(() -> new ClydoBidder("invalid_url", jacksonMapper));
+ }
+
+ @Test
+ public void makeHttpRequestsShouldMakeOneRequestPerImp() {
+ // given
+ final BidRequest bidRequest = BidRequest.builder()
+ .imp(asList(
+ givenImp(UnaryOperator.identity()),
+ givenImp(imp -> imp.id("321").ext(mapper.valueToTree(ExtPrebid
+ .of(null, ExtImpClydo.of("parentId", "us")))))))
+ .build();
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).hasSize(2)
+ .extracting(HttpRequest::getPayload)
+ .extracting(BidRequest::getImp)
+ .extracting(List::size)
+ .containsOnly(1);
+ assertThat(result.getValue())
+ .extracting(HttpRequest::getPayload)
+ .flatExtracting(BidRequest::getImp)
+ .extracting(Imp::getId)
+ .containsExactlyInAnyOrder("123", "321");
+ }
+
+ @Test
+ public void shouldMakeOneRequestWhenOneImpIsValidAndAnotherIsNot() {
+ // given
+ final BidRequest bidRequest = BidRequest.builder()
+ .imp(asList(givenImp(UnaryOperator.identity()), givenBadImp(UnaryOperator.identity())))
+ .build();
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getValue()).hasSize(1)
+ .extracting(HttpRequest::getPayload)
+ .flatExtracting(BidRequest::getImp)
+ .extracting(Imp::getId)
+ .containsExactly("123");
+ }
+
+ @Test
+ public void makeHttpRequestsShouldIncludeImpIds() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.id("imp1"));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue())
+ .extracting(HttpRequest::getPayload)
+ .flatExtracting(BidRequest::getImp)
+ .extracting(Imp::getId)
+ .containsExactly("imp1");
+ }
+
+ @Test
+ public void makeHttpRequestsShouldUseCorrectUri() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(UnaryOperator.identity());
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue())
+ .extracting(HttpRequest::getUri)
+ .containsExactly("http://region=us.clydo.io/partnerId=parentId");
+ }
+
+ @Test
+ public void makeHttpRequestsShouldReturnErrorIfImpExtCannotBeParsed() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(impBuilder ->
+ impBuilder.ext(mapper.createObjectNode().set("bidder", mapper.createArrayNode())));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getValue()).isEmpty();
+ assertThat(result.getErrors()).hasSize(1);
+ assertThat(result.getErrors().getFirst().getMessage()).startsWith("found no valid impressions");
+ }
+
+ @Test
+ public void makeHttpRequestsShouldReturnExpectedHeaders() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(UnaryOperator.identity());
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getValue()).hasSize(1).first()
+ .extracting(HttpRequest::getHeaders)
+ .satisfies(headers -> assertThat(headers.get(CONTENT_TYPE_HEADER))
+ .isEqualTo(APPLICATION_JSON_CONTENT_TYPE))
+ .satisfies(headers -> assertThat(headers.get(ACCEPT_HEADER))
+ .isEqualTo(APPLICATION_JSON_VALUE));
+ assertThat(result.getErrors()).isEmpty();
+ }
+
+ @Test
+ public void makeHttpRequestsShouldUseRegionUsInEndpoint() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(imp -> imp
+ .id("imp-us")
+ .ext(mapper.valueToTree(ExtPrebid.of(null,
+ ExtImpClydo.of("partner123", "us")))));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).hasSize(1).first()
+ .extracting(HttpRequest::getUri)
+ .isEqualTo("http://region=us.clydo.io/partnerId=partner123");
+ }
+
+ @Test
+ public void makeHttpRequestsShouldUseRegionEuInEndpointWithEuRegion() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(imp -> imp
+ .id("imp-us")
+ .ext(mapper.valueToTree(ExtPrebid.of(null,
+ ExtImpClydo.of("partner123", "eu")))));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).hasSize(1).first()
+ .extracting(HttpRequest::getUri)
+ .isEqualTo("http://region=eu.clydo.io/partnerId=partner123");
+ }
+
+ @Test
+ public void makeHttpRequestsShouldUseDefaultRegionUsWhenRegionIsNull() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(imp -> imp
+ .id("imp-null-region")
+ .ext(mapper.valueToTree(ExtPrebid.of(null,
+ ExtImpClydo.of("partner123", null)))));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).hasSize(1).first()
+ .extracting(HttpRequest::getUri)
+ .isEqualTo("http://region=us.clydo.io/partnerId=partner123");
+ }
+
+ @Test
+ public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException {
+ // given
+ final BidderCall httpCall = givenHttpCall(
+ mapper.writeValueAsString(null));
+
+ // when
+ final Result> result = target.makeBids(httpCall, null);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).isEmpty();
+ }
+
+ @Test
+ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() {
+ // given
+ final BidderCall httpCall = givenHttpCall("invalid");
+
+ // when
+ final Result> result = target.makeBids(httpCall, null);
+
+ // then
+ assertThat(result.getValue()).isEmpty();
+ assertThat(result.getErrors()).hasSize(1)
+ .allSatisfy(error -> {
+ assertThat(error.getMessage()).startsWith("Failed to decode: Unrecognized token 'invalid':");
+ assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response);
+ });
+ }
+
+ @Test
+ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException {
+ // given
+ final BidderCall httpCall = givenHttpCall(
+ mapper.writeValueAsString(BidResponse.builder().build()));
+
+ // when
+ final Result> result = target.makeBids(httpCall, null);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).isEmpty();
+ }
+
+ @Test
+ public void makeBidsShouldReturnBannerBid() throws JsonProcessingException {
+ // given
+ final BidRequest bidRequest = givenBidRequest(imp -> imp
+ .banner(Banner.builder().w(300).h(250).build()));
+ final BidderCall httpCall = givenHttpCall(
+ givenBidResponse(bidBuilder -> bidBuilder.impid("123")));
+
+ // when
+ final Result> result = target.makeBids(httpCall, bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(banner);
+ }
+
+ @Test
+ public void makeBidsShouldReturnVideoBid() throws JsonProcessingException {
+ // given
+ final BidRequest bidRequest = givenBidRequest(imp -> imp
+ .video(Video.builder().mimes(singletonList("video/mp4")).build()));
+ final BidderCall httpCall = givenHttpCall(givenBidResponse(bidBuilder -> bidBuilder.impid("123")));
+
+ // when
+ final Result> result = target.makeBids(httpCall, bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(video);
+ }
+
+ @Test
+ public void makeBidsShouldReturnNativeBid() throws JsonProcessingException {
+ // given
+ final BidRequest bidRequest = givenBidRequest(imp -> imp
+ .xNative(Native.builder().request("{\"assets\":[]}").build()));
+ final BidderCall httpCall = givenHttpCall(givenBidResponse(bidBuilder -> bidBuilder.impid("123")));
+
+ // when
+ final Result> result = target.makeBids(httpCall, bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(xNative);
+ }
+
+ @Test
+ public void makeBidsShouldReturnAudioBid() throws JsonProcessingException {
+ // given
+ final BidRequest bidRequest = givenBidRequest(imp -> imp
+ .banner(null)
+ .audio(Audio.builder().mimes(singletonList("audio/mp3")).build()));
+ final BidderCall httpCall = givenHttpCall(givenBidResponse(bidBuilder -> bidBuilder.impid("123")));
+
+ // when
+ final Result> result = target.makeBids(httpCall, bidRequest);
+
+ // then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(audio);
+ }
+
+ @Test
+ public void makeBidsShouldReturnErrorWhenImpHasNoMediaType() throws JsonProcessingException {
+ // given
+ final BidRequest bidRequest = givenBidRequest(imp -> imp.banner(null).video(null).xNative(null).audio(null));
+ final BidderCall httpCall = givenHttpCall(givenBidResponse(bidBuilder -> bidBuilder.impid("123")));
+
+ // when
+ final Result> result = target.makeBids(httpCall, bidRequest);
+
+ // then
+ assertThat(result.getValue()).isEmpty();
+ assertThat(result.getErrors()).hasSize(1).first()
+ .satisfies(error -> {
+ assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response);
+ assertThat(error.getMessage()).isEqualTo("Failed to get media type");
+ });
+ }
+
+ private static BidRequest givenBidRequest(
+ UnaryOperator bidRequestCustomizer,
+ UnaryOperator impCustomizer) {
+
+ return bidRequestCustomizer.apply(BidRequest.builder()
+ .imp(singletonList(givenImp(impCustomizer))))
+ .build();
+ }
+
+ private static BidRequest givenBidRequest(UnaryOperator impCustomizer) {
+ return givenBidRequest(UnaryOperator.identity(), impCustomizer);
+ }
+
+ private static Imp givenImp(UnaryOperator impCustomizer) {
+ return impCustomizer.apply(Imp.builder()
+ .id("123")
+ .ext(mapper.valueToTree(ExtPrebid.of(null,
+ ExtImpClydo.of("parentId", "us")))))
+ .build();
+ }
+
+ private static Imp givenBadImp(UnaryOperator impCustomizer) {
+ return impCustomizer.apply(Imp.builder()
+ .id("invalidImp")
+ .ext(mapper.createObjectNode().set("bidder", mapper.createArrayNode())))
+ .build();
+ }
+
+ private static String givenBidResponse(UnaryOperator bidCustomizer) throws JsonProcessingException {
+ final BidResponse bidResponse = BidResponse.builder()
+ .cur("USD")
+ .seatbid(singletonList(SeatBid.builder().bid(singletonList(bidCustomizer.apply(Bid.builder()).build()))
+ .build()))
+ .build();
+ return mapper.writeValueAsString(bidResponse);
+ }
+
+ private static BidderCall givenHttpCall(String body) {
+ return BidderCall.succeededHttp(
+ HttpRequest.builder().payload(null).build(),
+ HttpResponse.of(200, null, body),
+ null);
+ }
+}
diff --git a/src/test/java/org/prebid/server/bidder/nexx360/Nexx360BidderTest.java b/src/test/java/org/prebid/server/bidder/nexx360/Nexx360BidderTest.java
index 09c50589e19..bb06e21635b 100644
--- a/src/test/java/org/prebid/server/bidder/nexx360/Nexx360BidderTest.java
+++ b/src/test/java/org/prebid/server/bidder/nexx360/Nexx360BidderTest.java
@@ -28,6 +28,7 @@
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.function.UnaryOperator;
import static java.util.Collections.singletonList;
@@ -133,6 +134,30 @@ public void makeHttpRequestsShouldModifyImpExt() {
.containsExactly(expectedExt1, expectedExt2);
}
+ @Test
+ public void makeHttpRequestsShouldPreserveCustomFieldsInImpExt() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(
+ imp -> imp.id("imp1").ext(mapper.valueToTree(Map.of(
+ "bidder", ExtImpNexx360.of("tag1", "p1"),
+ "customField", "customValue"))));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ final ObjectNode expectedExt = mapper.valueToTree(Map.of(
+ "nexx360", ExtImpNexx360.of("tag1", "p1"),
+ "customField", "customValue"));
+
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).hasSize(1)
+ .extracting(HttpRequest::getPayload)
+ .flatExtracting(BidRequest::getImp)
+ .extracting(Imp::getExt)
+ .containsExactly(expectedExt);
+ }
+
@Test
public void makeHttpRequestsShouldModifyRequestExt() {
// given
diff --git a/src/test/java/org/prebid/server/bidder/smarthub/SmarthubBidderTest.java b/src/test/java/org/prebid/server/bidder/smarthub/SmarthubBidderTest.java
index 3f5630718e2..c9defbbd2e8 100644
--- a/src/test/java/org/prebid/server/bidder/smarthub/SmarthubBidderTest.java
+++ b/src/test/java/org/prebid/server/bidder/smarthub/SmarthubBidderTest.java
@@ -17,7 +17,6 @@
import org.prebid.server.bidder.model.HttpResponse;
import org.prebid.server.bidder.model.Result;
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
-import org.prebid.server.proto.openrtb.ext.request.adocean.ExtImpAdocean;
import org.prebid.server.proto.openrtb.ext.request.smarthub.ExtImpSmarthub;
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.proto.openrtb.ext.response.ExtBidResponse;
@@ -178,7 +177,7 @@ public void makeBidsShouldReturnErrorIfExtIncorrect() throws JsonProcessingExcep
// given
final BidderCall httpCall = givenHttpCall(givenBidRequest(identity()),
mapper.writeValueAsString(givenBidResponse(builder -> builder.ext(mapper.valueToTree(
- ExtPrebid.of(null, ExtImpAdocean.of("someEmitterDomain", "someMasterId", "someSlaveID")))))));
+ ExtPrebid.of(null, ExtImpSmarthub.of("someEmitterDomain", "someMasterId", "someSlaveID")))))));
// when
final Result> result = target.makeBids(httpCall, null);
diff --git a/src/test/java/org/prebid/server/bidder/teal/TealBidderTest.java b/src/test/java/org/prebid/server/bidder/teal/TealBidderTest.java
new file mode 100644
index 00000000000..200902919df
--- /dev/null
+++ b/src/test/java/org/prebid/server/bidder/teal/TealBidderTest.java
@@ -0,0 +1,273 @@
+package org.prebid.server.bidder.teal;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.iab.openrtb.request.Banner;
+import com.iab.openrtb.request.BidRequest;
+import com.iab.openrtb.request.Imp;
+import com.iab.openrtb.request.Native;
+import com.iab.openrtb.request.Publisher;
+import com.iab.openrtb.request.Site;
+import com.iab.openrtb.request.Video;
+import com.iab.openrtb.response.Bid;
+import com.iab.openrtb.response.BidResponse;
+import com.iab.openrtb.response.SeatBid;
+import org.junit.jupiter.api.Test;
+import org.prebid.server.VertxTest;
+import org.prebid.server.bidder.model.BidderBid;
+import org.prebid.server.bidder.model.BidderCall;
+import org.prebid.server.bidder.model.BidderError;
+import org.prebid.server.bidder.model.HttpRequest;
+import org.prebid.server.bidder.model.HttpResponse;
+import org.prebid.server.bidder.model.Result;
+import org.prebid.server.proto.openrtb.ext.ExtPrebid;
+import org.prebid.server.proto.openrtb.ext.request.teal.ExtImpTeal;
+import org.prebid.server.proto.openrtb.ext.response.BidType;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.function.UnaryOperator;
+import java.util.stream.Stream;
+
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+
+public class TealBidderTest extends VertxTest {
+
+ private static final String ENDPOINT_URL = "https://test.endpoint.com/";
+
+ private final TealBidder target = new TealBidder(ENDPOINT_URL, jacksonMapper);
+
+ @Test
+ public void creationShouldFailOnInvalidEndpointUrl() {
+ assertThatIllegalArgumentException().isThrownBy(() -> new TealBidder("invalid_url", jacksonMapper));
+ }
+
+ @Test
+ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(
+ imp -> imp.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getErrors()).hasSize(1)
+ .allSatisfy(error -> {
+ assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input);
+ assertThat(error.getMessage()).startsWith("Error parsing imp.ext for impression impId");
+ });
+ assertThat(result.getValue()).isEmpty();
+ }
+
+ @Test
+ public void makeHttpRequestsShouldReturnErrorIfAccountParamFailsValidation() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(
+ imp -> imp.id("imp1").ext(givenImpExt("", "placement")));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getErrors()).hasSize(1)
+ .allSatisfy(error -> {
+ assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input);
+ assertThat(error.getMessage()).startsWith("account parameter failed validation");
+ });
+ assertThat(result.getValue()).isEmpty();
+ }
+
+ @Test
+ public void makeHttpRequestsShouldReturnErrorIfPlacementParamFailsValidation() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(
+ imp -> imp.id("imp1").ext(givenImpExt("account", "")));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ // then
+ assertThat(result.getErrors()).hasSize(1)
+ .allSatisfy(error -> {
+ assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input);
+ assertThat(error.getMessage()).startsWith("placement parameter failed validation");
+ });
+ assertThat(result.getValue()).isEmpty();
+ }
+
+ @Test
+ public void makeHttpRequestsShouldMapParametersCorrectly() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(
+ Site.builder().publisher(Publisher.builder().domain("mydomain.com").build()).build(),
+ imp -> imp.id("imp1").ext(givenImpExt("account", "placement1")),
+ imp -> imp.id("imp2").ext(givenImpExt("account", null)));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ //then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue())
+ .extracting(HttpRequest::getPayload)
+ .extracting(BidRequest::getSite)
+ .extracting(Site::getPublisher)
+ .extracting(Publisher::getId)
+ .containsExactly("account");
+ assertThat(result.getValue())
+ .extracting(HttpRequest::getPayload)
+ .flatExtracting(BidRequest::getImp)
+ .extracting(Imp::getExt)
+ .element(0)
+ .extracting(ext -> ext.get("prebid"))
+ .extracting(prebid -> prebid.get("storedrequest"))
+ .extracting(storedRequest -> storedRequest.get("id"))
+ .extracting(JsonNode::textValue)
+ .isEqualTo("placement1");
+ assertThat(result.getValue())
+ .extracting(HttpRequest::getPayload)
+ .flatExtracting(BidRequest::getImp)
+ .extracting(Imp::getExt)
+ .element(1)
+ .extracting(ext -> ext.get("prebid"))
+ .isNull();
+ }
+
+ @Test
+ public void makeHttpRequestsShouldAddExtBidsPBSFlag() {
+ // given
+ final BidRequest bidRequest = givenBidRequest(
+ imp -> imp.id("imp1").ext(givenImpExt("account", "placement1")));
+
+ // when
+ final Result>> result = target.makeHttpRequests(bidRequest);
+
+ //then
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue())
+ .extracting(HttpRequest::getPayload)
+ .extracting(BidRequest::getExt)
+ .extracting(ext -> ext.getProperty("bids"))
+ .extracting(bids -> bids.get("pbs").toString())
+ .containsExactly("1");
+ }
+
+ @Test
+ public void makeBidsShouldReturnErrorWhenResponseBodyCouldNotBeParsed() {
+ // given
+ final BidderCall httpCall = BidderCall.succeededHttp(
+ HttpRequest.builder().build(),
+ HttpResponse.of(200, null, "invalid_json"),
+ null);
+
+ // when
+ final Result> result = target.makeBids(httpCall, null);
+
+ // then
+ assertThat(result.getErrors()).hasSize(1)
+ .allSatisfy(error -> {
+ assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response);
+ assertThat(error.getMessage()).startsWith("Failed to decode: Unrecognized token 'invalid_json'");
+ });
+ assertThat(result.getValue()).isEmpty();
+ }
+
+ @Test
+ public void makeBidsShouldReturnBannerBid() throws JsonProcessingException {
+ // given
+ final Bid responseBid = givenBid("imp1", 1, 1);
+ final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1").banner(Banner.builder().id("id").build()));
+ final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid));
+
+ // when
+ final Result> result = target.makeBids(httpCall, bidRequest);
+
+ // then
+ final Bid expectedBid = givenBid("imp1", 1, 1);
+
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).containsExactly(BidderBid.of(expectedBid, BidType.banner, "USD"));
+ }
+
+ @Test
+ public void makeBidsShouldReturnVideoBid() throws JsonProcessingException {
+ // given
+ final Bid responseBid = givenBid("imp1", 2, 1);
+ final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1").video(Video.builder().pos(1).build()));
+ final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid));
+
+ // when
+ final Result> result = target.makeBids(httpCall, bidRequest);
+
+ // then
+ final Bid expectedBid = givenBid("imp1", 2, 1);
+
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).containsExactly(BidderBid.of(expectedBid, BidType.video, "USD"));
+ }
+
+ @Test
+ public void makeBidsShouldReturnNativeBid() throws JsonProcessingException {
+ // given
+ final Bid responseBid = givenBid("imp1", 4, 1);
+ final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1").xNative(Native.builder().ver("1").build()));
+ final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid));
+
+ // when
+ final Result> result = target.makeBids(httpCall, bidRequest);
+
+ // then
+ final Bid expectedBid = givenBid("imp1", 4, 1);
+
+ assertThat(result.getErrors()).isEmpty();
+ assertThat(result.getValue()).containsExactly(BidderBid.of(expectedBid, BidType.xNative, "USD"));
+ }
+
+ private static BidRequest givenBidRequest(UnaryOperator impCustomizer) {
+ return givenBidRequest(null, impCustomizer);
+ }
+
+ private static BidRequest givenBidRequest(Site site, UnaryOperator... impCustomizers) {
+ final List imps = Stream.of(impCustomizers)
+ .map(customizer -> customizer.apply(Imp.builder().id("impId")).build())
+ .toList();
+ return BidRequest.builder().imp(imps).site(site).build();
+ }
+
+ private static ObjectNode givenImpExt(String account, String placement) {
+ return mapper.valueToTree(ExtPrebid.of(null, ExtImpTeal.of(account, placement)));
+ }
+
+ private static Bid givenBid(String id, Integer mType, int price) {
+ return Bid.builder()
+ .id("teal-" + id)
+ .impid(id)
+ .mtype(mType)
+ .price(BigDecimal.valueOf(price))
+ .adm("adm")
+ .w(300)
+ .h(250)
+ .adomain(singletonList("adomain.com"))
+ .ext(mapper.createObjectNode())
+ .build();
+ }
+
+ private static BidResponse givenBidResponse(List bids) {
+ return BidResponse.builder()
+ .cur("USD")
+ .seatbid(singletonList(SeatBid.builder().bid(bids).build()))
+ .build();
+ }
+
+ private static BidderCall givenHttpCall(BidRequest bidRequest, List bids)
+ throws JsonProcessingException {
+ return BidderCall.succeededHttp(
+ HttpRequest.builder().payload(bidRequest).build(),
+ HttpResponse.of(200, null, mapper.writeValueAsString(givenBidResponse(bids))),
+ null);
+ }
+}
diff --git a/src/test/java/org/prebid/server/it/AdoceanTest.java b/src/test/java/org/prebid/server/it/AdoceanTest.java
deleted file mode 100644
index d1b0da1f1fc..00000000000
--- a/src/test/java/org/prebid/server/it/AdoceanTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.prebid.server.it;
-
-import com.github.tomakehurst.wiremock.client.WireMock;
-import io.restassured.response.Response;
-import org.json.JSONException;
-import org.junit.jupiter.api.Test;
-import org.prebid.server.model.Endpoint;
-
-import java.io.IOException;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.get;
-import static java.util.Collections.singletonList;
-
-public class AdoceanTest extends IntegrationTest {
-
- @Test
- public void openrtb2AuctionShouldRespondWithBidsFromAdocean() throws IOException, JSONException {
-
- WIRE_MOCK_RULE.stubFor(get(WireMock.urlPathMatching("/adocean-exchange/_[0-9]*/ad.json"))
- .willReturn(aResponse().withBody(jsonFrom("openrtb2/adocean/test-adocean-bid-response-1.json"))));
-
- // when
- final Response response = responseFor("openrtb2/adocean/test-auction-adocean-request.json",
- Endpoint.openrtb2_auction);
-
- // then
- assertJsonEquals("openrtb2/adocean/test-auction-adocean-response.json", response, singletonList("adocean"));
- }
-}
diff --git a/src/test/java/org/prebid/server/it/MobuppsTest.java b/src/test/java/org/prebid/server/it/ClydoTest.java
similarity index 58%
rename from src/test/java/org/prebid/server/it/MobuppsTest.java
rename to src/test/java/org/prebid/server/it/ClydoTest.java
index 9987de46469..6bb262350a3 100644
--- a/src/test/java/org/prebid/server/it/MobuppsTest.java
+++ b/src/test/java/org/prebid/server/it/ClydoTest.java
@@ -13,21 +13,20 @@
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
import static java.util.Collections.singletonList;
-public class MobuppsTest extends IntegrationTest {
+public class ClydoTest extends IntegrationTest {
@Test
- public void openrtb2AuctionShouldRespondWithBidsFromTheMobupps() throws IOException, JSONException {
+ public void openrtb2AuctionShouldRespondWithBidsFromClydo() throws IOException, JSONException {
// given
- WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/mobupps-exchange"))
- .withRequestBody(equalToJson(jsonFrom("openrtb2/mobupps/test-mobupps-bid-request.json"), true, true))
- .willReturn(aResponse().withBody(jsonFrom("openrtb2/mobupps/test-mobupps-bid-response.json"))));
+ WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/clydo-exchange"))
+ .withRequestBody(equalToJson(jsonFrom("openrtb2/clydo/test-clydo-bid-request.json")))
+ .willReturn(aResponse().withBody(jsonFrom("openrtb2/clydo/test-clydo-bid-response.json"))));
// when
- final Response response = responseFor("openrtb2/mobupps/test-auction-mobupps-request.json",
+ final Response response = responseFor("openrtb2/clydo/test-auction-clydo-request.json",
Endpoint.openrtb2_auction);
// then
- assertJsonEquals("openrtb2/mobupps/test-auction-mobupps-response.json", response,
- singletonList("mobupps"));
+ assertJsonEquals("openrtb2/clydo/test-auction-clydo-response.json", response, singletonList("clydo"));
}
}
diff --git a/src/test/java/org/prebid/server/it/ProgxTest.java b/src/test/java/org/prebid/server/it/ProgxTest.java
index 6f77d217a86..c84a146ba7d 100644
--- a/src/test/java/org/prebid/server/it/ProgxTest.java
+++ b/src/test/java/org/prebid/server/it/ProgxTest.java
@@ -18,7 +18,7 @@ public class ProgxTest extends IntegrationTest {
@Test
public void openrtb2AuctionShouldRespondWithBidsFromProgx() throws IOException, JSONException {
// given
- WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/progx-exchange/connectionId"))
+ WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/progx-exchange/"))
.withRequestBody(equalToJson(jsonFrom("openrtb2/progx/test-progx-bid-request.json")))
.willReturn(aResponse().withBody(jsonFrom("openrtb2/progx/test-progx-bid-response.json"))));
diff --git a/src/test/java/org/prebid/server/it/VimayxTest.java b/src/test/java/org/prebid/server/it/RadianfusionTest.java
similarity index 59%
rename from src/test/java/org/prebid/server/it/VimayxTest.java
rename to src/test/java/org/prebid/server/it/RadianfusionTest.java
index ac7750065d0..52b401de7b3 100644
--- a/src/test/java/org/prebid/server/it/VimayxTest.java
+++ b/src/test/java/org/prebid/server/it/RadianfusionTest.java
@@ -14,23 +14,25 @@
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
import static java.util.Collections.singletonList;
-public class VimayxTest extends IntegrationTest {
+public class RadianfusionTest extends IntegrationTest {
@Test
- public void openrtb2AuctionShouldRespondWithBidsFromVimayx() throws IOException, JSONException {
+ public void openrtb2AuctionShouldRespondWithBidsFromRadianfusion() throws IOException, JSONException {
// given
- WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/vimayx-exchange"))
+ WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/radianfusion-exchange"))
.withQueryParam("host", equalTo("someUniquePartnerName"))
.withQueryParam("accountId", equalTo("someSeat"))
.withQueryParam("sourceId", equalTo("someToken"))
- .withRequestBody(equalToJson(jsonFrom("openrtb2/vimayx/test-vimayx-bid-request.json")))
- .willReturn(aResponse().withBody(jsonFrom("openrtb2/vimayx/test-vimayx-bid-response.json"))));
+ .withRequestBody(equalToJson(jsonFrom("openrtb2/radianfusion/test-radianfusion-bid-request.json")))
+ .willReturn(aResponse().withBody(
+ jsonFrom("openrtb2/radianfusion/test-radianfusion-bid-response.json"))));
// when
- final Response response = responseFor("openrtb2/vimayx/test-auction-vimayx-request.json",
+ final Response response = responseFor("openrtb2/radianfusion/test-auction-radianfusion-request.json",
Endpoint.openrtb2_auction);
// then
- assertJsonEquals("openrtb2/vimayx/test-auction-vimayx-response.json", response, singletonList("vimayx"));
+ assertJsonEquals("openrtb2/radianfusion/test-auction-radianfusion-response.json",
+ response, singletonList("radianfusion"));
}
}
diff --git a/src/test/java/org/prebid/server/it/TealTest.java b/src/test/java/org/prebid/server/it/TealTest.java
new file mode 100644
index 00000000000..bad01a8fb69
--- /dev/null
+++ b/src/test/java/org/prebid/server/it/TealTest.java
@@ -0,0 +1,32 @@
+package org.prebid.server.it;
+
+import io.restassured.response.Response;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.prebid.server.model.Endpoint;
+
+import java.io.IOException;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
+import static java.util.Collections.singletonList;
+
+public class TealTest extends IntegrationTest {
+
+ @Test
+ public void openrtb2AuctionShouldRespondWithBidsFromTeal() throws IOException, JSONException {
+ // given
+ WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/teal-exchange"))
+ .withRequestBody(equalToJson(jsonFrom("openrtb2/teal/test-teal-bid-request.json")))
+ .willReturn(aResponse().withBody(jsonFrom("openrtb2/teal/test-teal-bid-response.json"))));
+
+ // when
+ final Response response = responseFor("openrtb2/teal/test-auction-teal-request.json",
+ Endpoint.openrtb2_auction);
+
+ // then
+ assertJsonEquals("openrtb2/teal/test-auction-teal-response.json", response, singletonList("teal"));
+ }
+}
diff --git a/src/test/java/org/prebid/server/it/ThreeSixtyPlayVidTest.java b/src/test/java/org/prebid/server/it/ThreeSixtyPlayVidTest.java
new file mode 100644
index 00000000000..b87be532e46
--- /dev/null
+++ b/src/test/java/org/prebid/server/it/ThreeSixtyPlayVidTest.java
@@ -0,0 +1,37 @@
+package org.prebid.server.it;
+
+import io.restassured.response.Response;
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.prebid.server.model.Endpoint;
+
+import java.io.IOException;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
+import static java.util.Collections.singletonList;
+
+public class ThreeSixtyPlayVidTest extends IntegrationTest {
+
+ private static final String BID_REQUEST_JSON = "openrtb2/360playvid/test-360playvid-bid-request.json";
+ private static final String BID_RESPONSE_JSON = "openrtb2/360playvid/test-360playvid-bid-response.json";
+ private static final String AUCTION_REQUEST_JSON = "openrtb2/360playvid/test-auction-360playvid-request.json";
+ private static final String AUCTION_RESPONSE_JSON = "openrtb2/360playvid/test-auction-360playvid-response.json";
+
+ @Test
+ public void openrtb2AuctionShouldRespondWithBidsFromThreeSixtyPlayVid() throws IOException, JSONException {
+ // given
+ WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/360playvid-exchange"))
+ .withRequestBody(equalToJson(jsonFrom(BID_REQUEST_JSON)))
+ .willReturn(aResponse().withBody(jsonFrom(BID_RESPONSE_JSON))));
+
+ // when
+ final Response response = responseFor(AUCTION_REQUEST_JSON,
+ Endpoint.openrtb2_auction);
+
+ // then
+ assertJsonEquals(AUCTION_RESPONSE_JSON, response, singletonList("360playvid"));
+ }
+}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-360playvid-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-360playvid-bid-request.json
new file mode 100644
index 00000000000..dcf904ba566
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-360playvid-bid-request.json
@@ -0,0 +1,56 @@
+{
+ "id": "request_id",
+ "imp": [
+ {
+ "id": "imp_id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "secure": 1,
+ "ext": {
+ "bidder": {
+ "type": "publisher",
+ "placementId": "testPlacementId"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "www.example.com",
+ "page": "http://www.example.com",
+ "publisher": {
+ "domain": "example.com"
+ },
+ "ext": {
+ "amp": 0
+ }
+ },
+ "device": {
+ "ua": "userAgent",
+ "ip": "193.168.244.1"
+ },
+ "at": 1,
+ "tmax": "${json-unit.any-number}",
+ "cur": [
+ "USD"
+ ],
+ "source": {
+ "tid": "${json-unit.any-string}"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "ext": {
+ "prebid": {
+ "server": {
+ "externalurl": "http://localhost:8080",
+ "gvlid": 1,
+ "datacenter": "local",
+ "endpoint": "/openrtb2/auction"
+ }
+ }
+ }
+}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-360playvid-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-360playvid-bid-response.json
new file mode 100644
index 00000000000..180173549d8
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-360playvid-bid-response.json
@@ -0,0 +1,21 @@
+{
+ "id": "request_id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "bid_id",
+ "impid": "imp_id",
+ "price": 3.33,
+ "crid": "creativeId",
+ "mtype": 1,
+ "ext": {
+ "prebid": {
+ "type": "banner"
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-auction-360playvid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-auction-360playvid-request.json
new file mode 100644
index 00000000000..7f9d01b6a92
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-auction-360playvid-request.json
@@ -0,0 +1,23 @@
+{
+ "id": "request_id",
+ "imp": [
+ {
+ "id": "imp_id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "360playvid": {
+ "placementId": "testPlacementId"
+ }
+ }
+ }
+ ],
+ "tmax": 5000,
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-auction-360playvid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-auction-360playvid-response.json
new file mode 100644
index 00000000000..9072fe49720
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/360playvid/test-auction-360playvid-response.json
@@ -0,0 +1,38 @@
+{
+ "id": "request_id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "bid_id",
+ "impid": "imp_id",
+ "exp": 300,
+ "price": 3.33,
+ "crid": "creativeId",
+ "mtype": 1,
+ "ext": {
+ "origbidcpm": 3.33,
+ "prebid": {
+ "type": "banner",
+ "meta": {
+ "adaptercode": "360playvid"
+ }
+ }
+ }
+ }
+ ],
+ "seat": "360playvid",
+ "group": 0
+ }
+ ],
+ "cur": "USD",
+ "ext": {
+ "responsetimemillis": {
+ "360playvid": "{{ 360playvid.response_time_ms }}"
+ },
+ "prebid": {
+ "auctiontimestamp": 0
+ },
+ "tmaxrequest": 5000
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adocean/test-adocean-bid-response-1.json b/src/test/resources/org/prebid/server/it/openrtb2/adocean/test-adocean-bid-response-1.json
deleted file mode 100644
index 24304dd8da4..00000000000
--- a/src/test/resources/org/prebid/server/it/openrtb2/adocean/test-adocean-bid-response-1.json
+++ /dev/null
@@ -1,14 +0,0 @@
-[
- {
- "id": "adoceanmyaozpniqismex",
- "price": "10",
- "winurl": "https://win-url.com",
- "statsUrl": "https://stats-url.com",
- "code": " ",
- "currency": "USD",
- "width": "300",
- "height": "250",
- "crid": "0af345b42983cc4bc0",
- "error": "false"
- }
-]
\ No newline at end of file
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adocean/test-auction-adocean-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adocean/test-auction-adocean-request.json
deleted file mode 100644
index eccdf164b32..00000000000
--- a/src/test/resources/org/prebid/server/it/openrtb2/adocean/test-auction-adocean-request.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "id": "request_id",
- "imp": [
- {
- "id": "imp_id",
- "banner": {
- "w": 300,
- "h": 250
- },
- "ext": {
- "prebid": {
- "bidder": {
- "adocean": {
- "emitterPrefix": "myao",
- "masterId": "tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7",
- "slaveId": "adoceanmyaozpniqismex"
- }
- }
- }
- }
- }
- ],
- "tmax": 5000,
- "regs": {
- "ext": {
- "gdpr": 0
- }
- }
-}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adocean/test-auction-adocean-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adocean/test-auction-adocean-response.json
deleted file mode 100644
index ea7c23c5bb4..00000000000
--- a/src/test/resources/org/prebid/server/it/openrtb2/adocean/test-auction-adocean-response.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "id": "request_id",
- "seatbid": [
- {
- "bid": [
- {
- "id": "adoceanmyaozpniqismex",
- "impid": "imp_id",
- "exp": 300,
- "price": 10,
- "adm": " ",
- "crid": "0af345b42983cc4bc0",
- "w": 300,
- "h": 250,
- "ext": {
- "prebid": {
- "type": "banner",
- "meta": {
- "adaptercode": "adocean"
- }
- },
- "origbidcpm": 10,
- "origbidcur": "USD"
- }
- }
- ],
- "seat": "adocean",
- "group": 0
- }
- ],
- "cur": "USD",
- "ext": {
- "responsetimemillis": {
- "adocean": "{{ adocean.response_time_ms }}"
- },
- "tmaxrequest": 5000,
- "prebid": {
- "auctiontimestamp": 0
- }
- }
-}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-auction-clydo-request.json b/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-auction-clydo-request.json
new file mode 100644
index 00000000000..bfe3de91342
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-auction-clydo-request.json
@@ -0,0 +1,24 @@
+{
+ "id": "request_id",
+ "imp": [
+ {
+ "id": "imp_id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "clydo": {
+ "region": "us",
+ "partnerId": "testPartnerId"
+ }
+ }
+ }
+ ],
+ "tmax": 5000,
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ }
+}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-auction-clydo-response.json b/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-auction-clydo-response.json
new file mode 100644
index 00000000000..4b1494175f4
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-auction-clydo-response.json
@@ -0,0 +1,42 @@
+{
+ "id": "request_id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "bid_id",
+ "impid": "imp_id",
+ "exp": 300,
+ "price": 3.33,
+ "adm": "adm001",
+ "adid": "adid",
+ "cid": "cid",
+ "crid": "crid",
+ "w": 300,
+ "h": 250,
+ "ext": {
+ "prebid": {
+ "type": "banner",
+ "meta": {
+ "adaptercode": "clydo"
+ }
+ },
+ "origbidcpm": 3.33
+ }
+ }
+ ],
+ "seat": "clydo",
+ "group": 0
+ }
+ ],
+ "cur": "USD",
+ "ext": {
+ "responsetimemillis": {
+ "clydo": "{{ clydo.response_time_ms }}"
+ },
+ "prebid": {
+ "auctiontimestamp": 0
+ },
+ "tmaxrequest": 5000
+ }
+}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-clydo-bid-request.json
similarity index 50%
rename from src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-request.json
rename to src/test/resources/org/prebid/server/it/openrtb2/clydo/test-clydo-bid-request.json
index b1a0a5c0c8b..e43823a0317 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-request.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-clydo-bid-request.json
@@ -1,38 +1,37 @@
{
- "id": "test-auction-request",
+ "id": "request_id",
"imp": [
{
- "id": "imp1",
+ "id": "imp_id",
+ "secure": 1,
"banner": {
- "format": [
- {
- "w": 300,
- "h": 250
- }
- ]
+ "w": 300,
+ "h": 250
},
- "secure": 1,
"ext": {
"tid": "${json-unit.any-string}",
"bidder": {
- "adUnitId": 1,
- "auth": "123456"
+ "region": "us",
+ "partnerId": "testPartnerId"
}
}
}
],
+ "source": {
+ "tid": "${json-unit.any-string}"
+ },
"site": {
- "domain": "testpage.com",
- "page": "http://testpage.com",
+ "domain": "www.example.com",
+ "page": "http://www.example.com",
"publisher": {
- "domain": "testpage.com"
+ "domain": "example.com"
},
"ext": {
"amp": 0
}
},
"device": {
- "ua": "Mozilla/5.0",
+ "ua": "userAgent",
"ip": "193.168.244.1"
},
"at": 1,
@@ -40,12 +39,19 @@
"cur": [
"USD"
],
- "source": {
- "tid": "${json-unit.any-string}"
- },
"regs": {
"ext": {
"gdpr": 0
}
+ },
+ "ext": {
+ "prebid": {
+ "server": {
+ "externalurl": "http://localhost:8080",
+ "gvlid": 1,
+ "datacenter": "local",
+ "endpoint": "/openrtb2/auction"
+ }
+ }
}
}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-clydo-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-clydo-bid-response.json
new file mode 100644
index 00000000000..46fdbbec2ad
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/clydo/test-clydo-bid-response.json
@@ -0,0 +1,20 @@
+{
+ "id": "request_id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "bid_id",
+ "impid": "imp_id",
+ "price": 3.33,
+ "adid": "adid",
+ "crid": "crid",
+ "cid": "cid",
+ "adm": "adm001",
+ "h": 250,
+ "w": 300
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/easybid/test-easybid-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/easybid/test-easybid-bid-request.json
index a6a87d4012c..94c35c9da4d 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/easybid/test-easybid-bid-request.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/easybid/test-easybid-bid-request.json
@@ -9,6 +9,7 @@
},
"secure": 1,
"ext": {
+ "tid": "${json-unit.any-string}",
"nexx360": {
"placement": "placement"
}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-request.json b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-request.json
deleted file mode 100644
index 13f73b2a640..00000000000
--- a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-request.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "id": "test-auction-request",
- "imp": [
- {
- "id": "imp1",
- "banner": {
- "format": [
- {
- "w": 300,
- "h": 250
- }
- ]
- },
- "ext": {
- "mobupps": {
- "adUnitId": 1,
- "auth": "123456"
- }
- }
- }
- ],
- "site": {
- "page": "http://testpage.com"
- },
- "device": {
- "ua": "Mozilla/5.0"
- },
- "tmax": 5000,
- "regs": {
- "ext": {
- "gdpr": 0
- }
- }
-}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-response.json b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-response.json
deleted file mode 100644
index 6019f0e1752..00000000000
--- a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-auction-mobupps-response.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "id": "test-auction-request",
- "seatbid": [
- {
- "seat": "mobupps",
- "group": 0,
- "bid": [
- {
- "id": "bid1",
- "impid": "imp1",
- "price": 1.23,
- "adm": "",
- "nurl": "https://example.com/win?price=1.23",
- "crid": "creative1",
- "w": 300,
- "h": 250,
- "exp": 300,
- "mtype": 1,
- "ext": {
- "origbidcpm": 1.23,
- "origbidcur": "USD",
- "prebid": {
- "type": "banner",
- "meta": {
- "adaptercode": "mobupps"
- }
- }
- }
- }
- ]
- }
- ],
- "cur": "USD",
- "ext": {
- "responsetimemillis": {
- "mobupps": 0
- },
- "tmaxrequest": 5000,
- "prebid": {
- "auctiontimestamp": 0
- }
- }
-}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-response.json
deleted file mode 100644
index 735fcd2ee33..00000000000
--- a/src/test/resources/org/prebid/server/it/openrtb2/mobupps/test-mobupps-bid-response.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "id": "test-auction-request",
- "seatbid": [
- {
- "seat": "mobupps",
- "group": 0,
- "bid": [
- {
- "id": "bid1",
- "impid": "imp1",
- "price": 1.23,
- "adm": "",
- "nurl": "https://example.com/win?price=1.23",
- "crid": "creative1",
- "w": 300,
- "h": 250,
- "exp": 300,
- "mtype": 1,
- "ext": {
- "origbidcpm": 1.23,
- "origbidcur": "USD",
- "prebid": {
- "type": "banner"
- }
- }
- }
- ]
- }
- ],
- "cur": "USD",
- "ext": {
- "responsetimemillis": {
- "mobupps": 0
- },
- "tmaxrequest": 5000,
- "prebid": {
- "auctiontimestamp": 0
- }
- }
-}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/nexx360/test-nexx360-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/nexx360/test-nexx360-bid-request.json
index a6a87d4012c..94c35c9da4d 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/nexx360/test-nexx360-bid-request.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/nexx360/test-nexx360-bid-request.json
@@ -9,6 +9,7 @@
},
"secure": 1,
"ext": {
+ "tid": "${json-unit.any-string}",
"nexx360": {
"placement": "placement"
}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/oneaccord/test-1accord-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/oneaccord/test-1accord-bid-request.json
index a6a87d4012c..94c35c9da4d 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/oneaccord/test-1accord-bid-request.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/oneaccord/test-1accord-bid-request.json
@@ -9,6 +9,7 @@
},
"secure": 1,
"ext": {
+ "tid": "${json-unit.any-string}",
"nexx360": {
"placement": "placement"
}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/prismassp/test-prismassp-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/prismassp/test-prismassp-bid-request.json
index a6a87d4012c..94c35c9da4d 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/prismassp/test-prismassp-bid-request.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/prismassp/test-prismassp-bid-request.json
@@ -9,6 +9,7 @@
},
"secure": 1,
"ext": {
+ "tid": "${json-unit.any-string}",
"nexx360": {
"placement": "placement"
}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/progx/test-auction-progx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/progx/test-auction-progx-request.json
index 3c416a84304..c1994dd61a0 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/progx/test-auction-progx-request.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/progx/test-auction-progx-request.json
@@ -3,14 +3,13 @@
"imp": [
{
"id": "imp_id",
- "secure": 1,
"banner": {
- "w": 320,
+ "w": 300,
"h": 250
},
"ext": {
"progx": {
- "cId": "connectionId"
+ "placementId": "testPlacementId"
}
}
}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/progx/test-auction-progx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/progx/test-auction-progx-response.json
index b7437013277..59f6dffcf46 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/progx/test-auction-progx-response.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/progx/test-auction-progx-response.json
@@ -7,19 +7,17 @@
"id": "bid_id",
"impid": "imp_id",
"exp": 300,
- "price": 0.01,
- "adid": "2068416",
- "cid": "8048",
- "crid": "24080",
+ "price": 3.33,
+ "crid": "creativeId",
"mtype": 1,
"ext": {
+ "origbidcpm": 3.33,
"prebid": {
"type": "banner",
"meta": {
"adaptercode": "progx"
}
- },
- "origbidcpm": 0.01
+ }
}
}
],
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/progx/test-progx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/progx/test-progx-bid-request.json
index eb67f5687e5..dcf904ba566 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/progx/test-progx-bid-request.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/progx/test-progx-bid-request.json
@@ -3,22 +3,19 @@
"imp": [
{
"id": "imp_id",
- "secure": 1,
"banner": {
- "w": 320,
+ "w": 300,
"h": 250
},
+ "secure": 1,
"ext": {
- "tid": "${json-unit.any-string}",
"bidder": {
- "cId": "connectionId"
+ "type": "publisher",
+ "placementId": "testPlacementId"
}
}
}
],
- "source": {
- "tid": "${json-unit.any-string}"
- },
"site": {
"domain": "www.example.com",
"page": "http://www.example.com",
@@ -38,8 +35,13 @@
"cur": [
"USD"
],
+ "source": {
+ "tid": "${json-unit.any-string}"
+ },
"regs": {
+ "ext": {
"gdpr": 0
+ }
},
"ext": {
"prebid": {
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/progx/test-progx-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/progx/test-progx-bid-response.json
index 47d4f8718ea..180173549d8 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/progx/test-progx-bid-response.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/progx/test-progx-bid-response.json
@@ -1,19 +1,21 @@
{
- "id": "tid",
+ "id": "request_id",
"seatbid": [
{
"bid": [
{
- "crid": "24080",
- "adid": "2068416",
- "price": 0.01,
"id": "bid_id",
"impid": "imp_id",
- "cid": "8048",
- "mtype": 1
+ "price": 3.33,
+ "crid": "creativeId",
+ "mtype": 1,
+ "ext": {
+ "prebid": {
+ "type": "banner"
+ }
+ }
}
- ],
- "type": "banner"
+ ]
}
]
}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-auction-vimayx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-auction-radianfusion-request.json
similarity index 93%
rename from src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-auction-vimayx-request.json
rename to src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-auction-radianfusion-request.json
index 37f89d39672..c4c23330095 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-auction-vimayx-request.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-auction-radianfusion-request.json
@@ -8,7 +8,7 @@
"h": 250
},
"ext": {
- "vimayx": {
+ "radianfusion": {
"partnerName": "someUniquePartnerName",
"seat": "someSeat",
"token": "someToken"
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-auction-vimayx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-auction-radianfusion-response.json
similarity index 84%
rename from src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-auction-vimayx-response.json
rename to src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-auction-radianfusion-response.json
index 218b16cda60..701a84c994b 100644
--- a/src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-auction-vimayx-response.json
+++ b/src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-auction-radianfusion-response.json
@@ -20,20 +20,20 @@
"prebid": {
"type": "video",
"meta": {
- "adaptercode": "vimayx"
+ "adaptercode": "radianfusion"
}
}
}
}
],
- "seat": "vimayx",
+ "seat": "radianfusion",
"group": 0
}
],
"cur": "USD",
"ext": {
"responsetimemillis": {
- "vimayx": "{{ vimayx.response_time_ms }}"
+ "radianfusion": "{{ radianfusion.response_time_ms }}"
},
"prebid": {
"auctiontimestamp": 0
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-vimayx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-radianfusion-bid-request.json
similarity index 100%
rename from src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-vimayx-bid-request.json
rename to src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-radianfusion-bid-request.json
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-vimayx-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-radianfusion-bid-response.json
similarity index 100%
rename from src/test/resources/org/prebid/server/it/openrtb2/vimayx/test-vimayx-bid-response.json
rename to src/test/resources/org/prebid/server/it/openrtb2/radianfusion/test-radianfusion-bid-response.json
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/teal/test-auction-teal-request.json b/src/test/resources/org/prebid/server/it/openrtb2/teal/test-auction-teal-request.json
new file mode 100644
index 00000000000..af84f5cf1b7
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/teal/test-auction-teal-request.json
@@ -0,0 +1,44 @@
+{
+ "id": "test-request-banner",
+ "imp": [
+ {
+ "id": "test-imp-banner",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ]
+ },
+ "ext": {
+ "teal": {
+ "account": "test-account",
+ "placement": "test-placement300x250"
+ }
+ }
+ }
+ ],
+ "site": {
+ "id": "demo-site",
+ "domain": "example.com",
+ "page": "https://example.com/demo",
+ "publisher": {
+ "id": "demo-publisher"
+ }
+ },
+ "device": {
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
+ "ip": "192.0.2.1",
+ "language": "en",
+ "dnt": 0
+ },
+ "user": {
+ "id": "demo-user"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ }
+}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/teal/test-auction-teal-response.json b/src/test/resources/org/prebid/server/it/openrtb2/teal/test-auction-teal-response.json
new file mode 100644
index 00000000000..e183f1a0330
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/teal/test-auction-teal-response.json
@@ -0,0 +1,41 @@
+{
+ "id": "test-request-banner",
+ "seatbid": [
+ {
+ "seat": "teal",
+ "bid": [
+ {
+ "id": "test-imp-banner",
+ "impid": "test-imp-banner",
+ "price": 2.50,
+ "adm": "Teal Demo Ad
",
+ "w": 300,
+ "h": 250,
+ "crid": "demo-creative-123",
+ "exp": 300,
+ "ext": {
+ "origbidcpm": 2.50,
+ "origbidcur": "USD",
+ "prebid": {
+ "type": "banner",
+ "meta": {
+ "adaptercode": "teal"
+ }
+ }
+ }
+ }
+ ],
+ "group": 0
+ }
+ ],
+ "cur": "USD",
+ "ext": {
+ "responsetimemillis": {
+ "teal": "{{ teal.response_time_ms }}"
+ },
+ "prebid": {
+ "auctiontimestamp": 0
+ },
+ "tmaxrequest": 5000
+ }
+}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/teal/test-teal-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/teal/test-teal-bid-request.json
new file mode 100644
index 00000000000..c26cb49987d
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/teal/test-teal-bid-request.json
@@ -0,0 +1,77 @@
+{
+ "id": "test-request-banner",
+ "imp": [
+ {
+ "id": "test-imp-banner",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ]
+ },
+ "secure": 1,
+ "ext": {
+ "tid": "${json-unit.any-string}",
+ "bidder": {
+ "account": "test-account",
+ "placement": "test-placement300x250"
+ },
+ "prebid": {
+ "storedrequest": {
+ "id": "test-placement300x250"
+ }
+ }
+ }
+ }
+ ],
+ "site": {
+ "id": "demo-site",
+ "domain": "example.com",
+ "page": "https://example.com/demo",
+ "publisher": {
+ "id": "test-account",
+ "domain": "example.com"
+ },
+ "ext": {
+ "amp": 0
+ }
+ },
+ "device": {
+ "dnt": 0,
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
+ "ip": "192.0.2.1",
+ "language": "en"
+ },
+ "user": {
+ "id": "demo-user"
+ },
+ "at": 1,
+ "tmax": "${json-unit.any-number}",
+ "cur": [
+ "USD"
+ ],
+ "source": {
+ "tid": "${json-unit.any-string}"
+ },
+ "regs": {
+ "gdpr": 0
+ },
+ "ext": {
+ "prebid": {
+ "channel": {
+ "name": "web"
+ },
+ "server": {
+ "externalurl": "http://localhost:8080",
+ "gvlid": 1,
+ "datacenter": "local",
+ "endpoint": "/openrtb2/auction"
+ }
+ },
+ "bids": {
+ "pbs": 1
+ }
+ }
+}
diff --git a/src/test/resources/org/prebid/server/it/openrtb2/teal/test-teal-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/teal/test-teal-bid-response.json
new file mode 100644
index 00000000000..2c5a13641ff
--- /dev/null
+++ b/src/test/resources/org/prebid/server/it/openrtb2/teal/test-teal-bid-response.json
@@ -0,0 +1,29 @@
+{
+ "id": "test-request-banner",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "test-imp-banner",
+ "impid": "test-imp-banner",
+ "price": 2.50,
+ "adm": "Teal Demo Ad
",
+ "w": 300,
+ "h": 250,
+ "crid": "demo-creative-123",
+ "exp": 300,
+ "ext": {
+ "origbidcpm": 2.50,
+ "origbidcur": "USD",
+ "prebid": {
+ "type": "banner",
+ "meta": {
+ "adaptercode": "teal"
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/test/resources/org/prebid/server/it/test-application.properties b/src/test/resources/org/prebid/server/it/test-application.properties
index 2a3ffe37083..ae0a683c9a7 100644
--- a/src/test/resources/org/prebid/server/it/test-application.properties
+++ b/src/test/resources/org/prebid/server/it/test-application.properties
@@ -62,8 +62,6 @@ adapters.admixer.endpoint=http://localhost:8090/admixer-exchange
adapters.adnuntius.enabled=true
adapters.adnuntius.endpoint=http://localhost:8090/adnuntius-exchange
adapters.adnuntius.eu-endpoint=http://localhost:8090/adnuntius-exchange-eu
-adapters.adocean.enabled=true
-adapters.adocean.endpoint=http://localhost:8090/adocean-exchange
adapters.elementaltv.enabled=true
adapters.elementaltv.endpoint=http://localhost:8090/elementaltv-exchange
adapters.adpone.enabled=true
@@ -76,8 +74,6 @@ adapters.adverxo.aliases.adport.enabled=true
adapters.adverxo.aliases.adport.endpoint=http://localhost:8090/adport-exchange
adapters.adverxo.aliases.bidsmind.enabled=true
adapters.adverxo.aliases.bidsmind.endpoint=http://localhost:8090/bidsmind-exchange
-adapters.adverxo.aliases.mobupps.enabled=true
-adapters.adverxo.aliases.mobupps.endpoint=http://localhost:8090/mobupps-exchange
adapters.adview.enabled=true
adapters.adview.endpoint=http://localhost:8090/adview-exchange?accountId={{AccountId}}
adapters.adprime.enabled=true
@@ -191,6 +187,8 @@ adapters.brave.enabled=true
adapters.brave.endpoint=http://localhost:8090/brave-exchange
adapters.bwx.enabled=true
adapters.bwx.endpoint=http://localhost:8090/bwx-exchange
+adapters.clydo.enabled=true
+adapters.clydo.endpoint=http://localhost:8090/clydo-exchange
adapters.cointraffic.enabled=true
adapters.cointraffic.endpoint=http://localhost:8090/cointraffic-exchange
adapters.connatix.enabled=true
@@ -521,8 +519,6 @@ adapters.smarthub.aliases.jdpmedia.enabled=true
adapters.smarthub.aliases.jdpmedia.endpoint=http://localhost:8090/jdpmedia-exchange?host={{Host}}&accountId={{AccountID}}&sourceId={{SourceId}}
adapters.smarthub.aliases.tredio.enabled=true
adapters.smarthub.aliases.tredio.endpoint=http://localhost:8090/tredio-exchange?host={{Host}}&accountId={{AccountID}}&sourceId={{SourceId}}
-adapters.smarthub.aliases.vimayx.enabled=true
-adapters.smarthub.aliases.vimayx.endpoint=http://localhost:8090/vimayx-exchange?host={{Host}}&accountId={{AccountID}}&sourceId={{SourceId}}
adapters.smarthub.aliases.felixads.enabled=true
adapters.smarthub.aliases.felixads.endpoint=http://localhost:8090/felixads-exchange?host={{Host}}&accountId={{AccountID}}&sourceId={{SourceId}}
adapters.smarthub.aliases.jambojar.enabled=true
@@ -533,6 +529,8 @@ adapters.smarthub.aliases.addigi.enabled=true
adapters.smarthub.aliases.addigi.endpoint=http://localhost:8090/addigi-exchange
adapters.smarthub.aliases.artechnology.enabled=true
adapters.smarthub.aliases.artechnology.endpoint=http://localhost:8090/artechnology-exchange?host={{Host}}&accountId={{AccountID}}&sourceId={{SourceId}}
+adapters.smarthub.aliases.radianfusion.enabled=true
+adapters.smarthub.aliases.radianfusion.endpoint=http://localhost:8090/radianfusion-exchange?host={{Host}}&accountId={{AccountID}}&sourceId={{SourceId}}
adapters.smartyads.enabled=true
adapters.smartyads.endpoint=http://localhost:8090/smartyads-exchange
adapters.smilewanted.enabled=true
@@ -573,10 +571,14 @@ adapters.tappx.enabled=true
adapters.tappx.endpoint=http://localhost:8090/tappx-exchange
adapters.teads.enabled=true
adapters.teads.endpoint=http://localhost:8090/teads-exchange
+adapters.teal.enabled=true
+adapters.teal.endpoint=http://localhost:8090/teal-exchange
adapters.telaria.enabled=true
adapters.telaria.endpoint=http://localhost:8090/telaria-exchange/
adapters.teqblaze.enabled=true
adapters.teqblaze.endpoint=http://localhost:8090/teqblaze-exchange
+adapters.teqblaze.aliases.360playvid.enabled=true
+adapters.teqblaze.aliases.360playvid.endpoint=http://localhost:8090/360playvid-exchange
adapters.teqblaze.aliases.pinkLion.enabled=true
adapters.teqblaze.aliases.pinkLion.endpoint=http://localhost:8090/pinkLion-exchange
adapters.teqblaze.aliases.rocketlab.enabled=true
@@ -585,6 +587,8 @@ adapters.teqblaze.aliases.appStockSSP.enabled=true
adapters.teqblaze.aliases.appStockSSP.endpoint=http://localhost:8090/appstockssp-exchange
adapters.teqblaze.aliases.gravite.enabled=true
adapters.teqblaze.aliases.gravite.endpoint=http://localhost:8090/gravite-exchange
+adapters.teqblaze.aliases.progx.enabled=true
+adapters.teqblaze.aliases.progx.endpoint=http://localhost:8090/progx-exchange/
adapters.theadx.enabled=true
adapters.theadx.endpoint=http://localhost:8090/theadx-exchange
adapters.tradplus.enabled=true
@@ -637,8 +641,6 @@ adapters.xeworks.aliases.adipolo.enabled=true
adapters.xeworks.aliases.adipolo.endpoint=http://localhost:8090/adipolo-exchange
adapters.vidazoo.enabled=true
adapters.vidazoo.endpoint=http://localhost:8090/vidazoo-exchange/
-adapters.vidazoo.aliases.progx.enabled=true
-adapters.vidazoo.aliases.progx.endpoint=http://localhost:8090/progx-exchange/
adapters.vidazoo.aliases.omnidex.enabled=true
adapters.vidazoo.aliases.omnidex.endpoint=http://localhost:8090/omnidex-exchange/
adapters.vidazoo.aliases.tagoras.enabled=true