diff --git a/.github/workflows/pr-module-functional-tests.yml b/.github/workflows/pr-module-functional-tests.yml index 6741e45b1d6..42ba6be69c7 100644 --- a/.github/workflows/pr-module-functional-tests.yml +++ b/.github/workflows/pr-module-functional-tests.yml @@ -60,6 +60,7 @@ jobs: use-actions-summary: 'true' list-suites: 'failed' list-tests: 'failed' + list-files: 'failed' fail-on-error: true fail-on-empty: true token: ${{ secrets.GITHUB_TOKEN }} diff --git a/pom.xml b/pom.xml index 1012e1493ab..f9f2e5b8117 100644 --- a/pom.xml +++ b/pom.xml @@ -615,6 +615,7 @@ ${project.version} 5 + false false diff --git a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy index 1061cf4a348..1ebb874c6a7 100644 --- a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy @@ -14,7 +14,7 @@ enum BidderName { ALIAS_UPPER_CASE("ALIAS"), GENERIC_CAMEL_CASE("GeNerIc"), GENERIC("generic"), - GENER_X("gener_x"), + GENER_X("gener-x"), MAGNITE("magnite"), APPNEXUS("appnexus"), MAGNITE_ALIAS("magniteAlias"), diff --git a/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy b/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy index b583363974c..98a8187cf2e 100644 --- a/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/bidder/GeneralBidderAdapter.groovy @@ -11,4 +11,6 @@ class GeneralBidderAdapter extends Generic { String demandSource @JsonProperty("bc") BidderName bidderCode + @JsonProperty("placement_id") + String placementId } diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/FetchStatus.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/AnalyticTagStatus.groovy similarity index 93% rename from src/test/groovy/org/prebid/server/functional/model/request/auction/FetchStatus.groovy rename to src/test/groovy/org/prebid/server/functional/model/request/auction/AnalyticTagStatus.groovy index 6eec49cf39d..3f6dcaf412e 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/FetchStatus.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/AnalyticTagStatus.groovy @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonValue import groovy.transform.ToString @ToString -enum FetchStatus { +enum AnalyticTagStatus { NONE, SUCCESS, TIMEOUT, INPROGRESS, ERROR, SUCCESS_ALLOW, SUCCESS_BLOCK, SKIPPED, RUN diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy index 5ea7a7d3270..246b2993d5b 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy @@ -15,7 +15,7 @@ class Bidder { @JsonProperty("ALIAS") Generic aliasUpperCase Generic generic - @JsonProperty("gener_x") + @JsonProperty("gener-x") Generic generX @JsonProperty("GeNerIc") Generic genericCamelCase diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/ExtPrebidFloors.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/ExtPrebidFloors.groovy index c0c80038f5c..0ef7a96e7c6 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/ExtPrebidFloors.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/ExtPrebidFloors.groovy @@ -12,7 +12,7 @@ class ExtPrebidFloors { Boolean enabled Location location - FetchStatus fetchStatus + AnalyticTagStatus fetchStatus Boolean skipped Currency floorMinCur BigDecimal floorMin diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticResult.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticResult.groovy index a8b737a848a..57d62801746 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticResult.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticResult.groovy @@ -4,11 +4,11 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.EqualsAndHashCode import groovy.transform.ToString -import org.prebid.server.functional.model.request.auction.FetchStatus +import org.prebid.server.functional.model.request.auction.AnalyticTagStatus import org.prebid.server.functional.model.request.auction.Imp -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS_BLOCK +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS_BLOCK @ToString(includeNames = true, ignoreNulls = true) @JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) @@ -16,7 +16,7 @@ import static org.prebid.server.functional.model.request.auction.FetchStatus.SUC class AnalyticResult { String name - FetchStatus status + AnalyticTagStatus status List results static AnalyticResult buildFromImp(Imp imp) { diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticTagStatus.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticTagStatus.groovy new file mode 100644 index 00000000000..f7575677ce3 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticTagStatus.groovy @@ -0,0 +1,13 @@ +package org.prebid.server.functional.model.response.auction + +import com.fasterxml.jackson.annotation.JsonValue + +enum AnalyticTagStatus { + + NONE, LOOKUP, CONTROL, SUCCESS, ERROR, SUCCESS_ALLOW, SUCCESS_BLOCK, SKIPPED, RUN + + @JsonValue + String getValue() { + name().toLowerCase().replace('_', '-') + } +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticsTagActivity.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticsTagActivity.groovy index 6fd41583617..2ee172e41e3 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticsTagActivity.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticsTagActivity.groovy @@ -3,13 +3,13 @@ package org.prebid.server.functional.model.response.auction import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString -import org.prebid.server.functional.model.request.auction.FetchStatus +import org.prebid.server.functional.model.request.auction.AnalyticTagStatus @ToString(includeNames = true, ignoreNulls = true) @JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) class AnalyticsTagActivity { ModuleActivityName name - FetchStatus status + AnalyticTagStatus status List results } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticsTagActivityResult.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticsTagActivityResult.groovy index a439d6411c2..59d0948519c 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticsTagActivityResult.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/AnalyticsTagActivityResult.groovy @@ -3,13 +3,13 @@ package org.prebid.server.functional.model.response.auction import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString -import org.prebid.server.functional.model.request.auction.FetchStatus +import org.prebid.server.functional.model.request.auction.AnalyticTagStatus @ToString(includeNames = true, ignoreNulls = true) @JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) class AnalyticsTagActivityResult { - FetchStatus status + AnalyticTagStatus status AnalyticsTagActivityValue values AppliedTo appliedTo } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy index 81dcd788b7d..04ac22ee511 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy @@ -6,6 +6,7 @@ enum ErrorType { GENERAL("general"), GENERIC("generic"), + GENER_X("gener-x"), GENERIC_CAMEL_CASE("GeNerIc"), MAGNITE("magnite"), APPNEXUS("appnexus"), diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/ImpResult.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/ImpResult.groovy index 8740e415f47..e12db6d5404 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/ImpResult.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/ImpResult.groovy @@ -4,14 +4,14 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.EqualsAndHashCode import groovy.transform.ToString -import org.prebid.server.functional.model.request.auction.FetchStatus +import org.prebid.server.functional.model.request.auction.AnalyticTagStatus @ToString(includeNames = true, ignoreNulls = true) @JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) @EqualsAndHashCode class ImpResult { - FetchStatus status + AnalyticTagStatus status ModuleValue values AppliedTo appliedTo } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/ModuleActivityName.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/ModuleActivityName.groovy index 8711bd395c6..10705cc6dcf 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/ModuleActivityName.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/ModuleActivityName.groovy @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonValue enum ModuleActivityName { - ORTB2_BLOCKING('enforce-blocking'), + PB_ORTB2_BLOCKING('enforce-blocking'), REJECT_RICHMEDIA('reject-richmedia'), AB_TESTING('core-module-abtests') diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy index c873c1a03f3..8786d3e6869 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy @@ -1,6 +1,6 @@ package org.prebid.server.functional.testcontainers - +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.testcontainers.containers.MySQLContainer import org.testcontainers.containers.PostgreSQLContainer diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsServiceFactory.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsServiceFactory.groovy index 60ca02ad762..d1c5f8cbbc9 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsServiceFactory.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsServiceFactory.groovy @@ -1,73 +1,104 @@ package org.prebid.server.functional.testcontainers import org.prebid.server.functional.service.PrebidServerService -import org.prebid.server.functional.testcontainers.container.NetworkServiceContainer +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.testcontainers.container.PrebidServerContainer -import org.prebid.server.functional.util.SystemProperties import org.testcontainers.images.builder.Transferable +import static org.prebid.server.functional.testcontainers.PbsServiceFactory.ContainerPolicy.LRU +import static org.prebid.server.functional.testcontainers.PbsServiceFactory.ContainerPolicy.PERSISTENT +import static org.prebid.server.functional.util.SystemProperties.DEBUG_ENABLED +import static org.prebid.server.functional.util.SystemProperties.MAX_CONTAINER import static org.prebid.server.functional.util.SystemProperties.USE_FIXED_CONTAINER_PORTS -// TODO make container instance into a POGO and add the ability for any given container to live through stopContainers() class PbsServiceFactory { - private static final Map, PrebidServerContainer> containers = [:] private static final int MAX_CONTAINER_COUNT = maxContainerCount - private final NetworkServiceContainer networkServiceContainer + private static final Map containers = + new LinkedHashMap<>(16, 0.75f, true) - PbsServiceFactory(NetworkServiceContainer networkServiceContainer) { - this.networkServiceContainer = networkServiceContainer + // Will be removed in 5.0 + @Deprecated(forRemoval = true) + static PrebidServerService getService(Map config, + Map additionalFiles = [:], + ContainerPolicy policy = LRU) { + getService(new PbsContainerConfig(config, additionalFiles), policy) } - static PrebidServerService getService(Map config, Map additionalFiles = [:]) { - if (containers.containsKey(config)) { - def container = containers.get(config) - container.refresh() - return new PrebidServerService(container) - } else { - if (containers.size() == 1 && MAX_CONTAINER_COUNT == 1) { - def container = containers.entrySet().first() - remove([(container.key): container.value]) - } else if (containers.size() >= MAX_CONTAINER_COUNT) { - def container = containers.find { !it.key.isEmpty() } - remove([(container.key): container.value]) - } - def pbsContainer = new PrebidServerContainer(config) - if (!additionalFiles.isEmpty()) { - additionalFiles.each { k, v -> pbsContainer.withCopyToContainer(v, k) } - } - pbsContainer.start() - containers.put(config, pbsContainer) - return new PrebidServerService(pbsContainer) + static PrebidServerService getService(PbsContainerConfig config, + ContainerPolicy policy = LRU) { + def cached = containers.remove(config) + if (cached) { + cached.container.refresh() + cached.persistent |= policy == PERSISTENT + containers.put(config, cached) + return new PrebidServerService(cached.container) } + evictIfNeeded() + def container = new PrebidServerContainer(config, DEBUG_ENABLED) + container.start() + containers.put(config, new CachedContainer( + container: container, + persistent: policy == PERSISTENT + )) + return new PrebidServerService(container) } - private static PrebidServerContainer getContainer(Map config) { - containers.get(config) + private static void evictIfNeeded() { + if (containers.size() < MAX_CONTAINER_COUNT) { + return + } + + def eldest = containers.entrySet().find { !it.value.persistent } + if (!eldest) { + throw new IllegalStateException("All container slots are persistent") + } + + eldest.value.container.stop() + containers.remove(eldest.key) } static void stopContainers() { - def containers = containers.findAll { it.key != [:] } - remove(containers) + def iterator = containers.entrySet().iterator() + + while (iterator.hasNext()) { + def entry = iterator.next() + if (!entry.value.persistent) { + entry.value.container.stop() + iterator.remove() + } + } } - static void removeContainer(Map config) { - def container = containers.get(config) - container.stop() - containers.remove(config) + // Will be removed in 5.0. + @Deprecated(forRemoval = true) + static void removeContainer(Map config) { + removeContainer(new PbsContainerConfig(config)) } - private static void remove(Map, PrebidServerContainer> map) { - map.each { key, value -> - value.stop() - containers.remove(key) - } + static void removeContainer(PbsContainerConfig config) { + containers.remove(config)?.container?.stop() + } + + static void stopAllContainers() { + containers.values().each { it.container.stop() } + containers.clear() } private static int getMaxContainerCount() { USE_FIXED_CONTAINER_PORTS ? 1 - : SystemProperties.getPropertyOrDefault("tests.max-container-count", 5) + : MAX_CONTAINER + } + + private static class CachedContainer { + PrebidServerContainer container + boolean persistent + } + + enum ContainerPolicy { + PERSISTENT, + LRU } } diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/container/PbsContainerConfig.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PbsContainerConfig.groovy new file mode 100644 index 00000000000..9a1c6b30bd9 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PbsContainerConfig.groovy @@ -0,0 +1,42 @@ +package org.prebid.server.functional.testcontainers.container + +import groovy.transform.EqualsAndHashCode +import org.testcontainers.images.builder.Transferable + + +@EqualsAndHashCode + +class PbsContainerConfig { + + final Map extraProperties + final Map additionalFiles + + PbsContainerConfig(Map extraProperties = [:], + Map additionalFiles = [:]) { + this.extraProperties = extraProperties.collectEntries { key, value -> + [(key.toString()): value?.toString()] + }.asImmutable() + this.additionalFiles = additionalFiles.asImmutable() + } + + PbsContainerConfig plus(Map properties) { + new PbsContainerConfig( + [:] << extraProperties << properties, + additionalFiles + ) + } + + PbsContainerConfig plus(PbsContainerConfig other) { + new PbsContainerConfig( + [:] << extraProperties << other.extraProperties, + [:] << additionalFiles << other.additionalFiles + ) + } + + PbsContainerConfig withFiles(Map files) { + new PbsContainerConfig( + extraProperties, + [:] << additionalFiles << files + ) + } +} diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy index 5a177572122..a71fd0e24dc 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy @@ -12,29 +12,32 @@ import static org.prebid.server.functional.testcontainers.PbsConfig.DEFAULT_ENV class PrebidServerContainer extends GenericContainer { - public static final String ADMIN_ENDPOINT_USERNAME = "admin" - public static final String ADMIN_ENDPOINT_PASSWORD = "admin" - public static final String APP_WORKDIR = "/app/prebid-server/" - public static final int PROMETHEUS_PORT = 8070 - - private static final int DEFAULT_PORT = 8080 - private static final int DEFAULT_ADMIN_PORT = 8060 - private static final int DEFAULT_DEBUG_PORT = 8000 - private static final int PORT = SystemProperties.getPropertyOrDefault("port", DEFAULT_PORT) - private static final int ADMIN_PORT = SystemProperties.getPropertyOrDefault("admin.port", DEFAULT_ADMIN_PORT) - private static final int DEBUG_PORT = SystemProperties.getPropertyOrDefault("debug.port", DEFAULT_DEBUG_PORT) + static final String ADMIN_ENDPOINT_USERNAME = "admin" + static final String ADMIN_ENDPOINT_PASSWORD = "admin" + static final String APP_WORKDIR = "/app/prebid-server/" + static final int PROMETHEUS_PORT = 8070 + + private static final int PORT = SystemProperties.getPropertyOrDefault("port", 8080) + private static final int ADMIN_PORT = SystemProperties.getPropertyOrDefault("admin.port", 8060) + private static final int DEBUG_PORT = SystemProperties.getPropertyOrDefault("debug.port", 8000) private static final String PBS_DOCKER_IMAGE_NAME = "prebid/prebid-server:latest" - PrebidServerContainer(Map customConfig) { + private final boolean debugEnabled + + PrebidServerContainer(PbsContainerConfig config, boolean debugEnabled = false) { super(PBS_DOCKER_IMAGE_NAME) - withExposedPorts(PORT, DEBUG_PORT, ADMIN_PORT, PROMETHEUS_PORT) + this.debugEnabled = debugEnabled + def ports = [PORT, ADMIN_PORT, PROMETHEUS_PORT] + if (debugEnabled) { + ports << DEBUG_PORT + } + withExposedPorts(*ports) withFixedPorts() withStartupAttempts(3) waitingFor(Wait.forHttp(STATUS.value) .forPort(PORT) .forStatusCode(200)) - withDebug() withNetwork(Dependencies.network) def commonConfig = [:] << DEFAULT_ENV << PbsConfig.defaultBiddersConfig @@ -46,23 +49,46 @@ class PrebidServerContainer extends GenericContainer { << PbsConfig.mySqlConfig << PbsConfig.targetingConfig withConfig(commonConfig) - withConfig(customConfig) + withConfig(config.extraProperties) + + config.additionalFiles.each { path, file -> + withCopyToContainer(file, path) + } + + if (debugEnabled) { + withDebug() + } } private void withFixedPorts() { - if (SystemProperties.USE_FIXED_CONTAINER_PORTS) { - addFixedExposedPort(PORT, PORT) - addFixedExposedPort(ADMIN_PORT, ADMIN_PORT) + if (!SystemProperties.USE_FIXED_CONTAINER_PORTS) { + return + } + addFixedExposedPort(PORT, PORT) + addFixedExposedPort(ADMIN_PORT, ADMIN_PORT) + if (debugEnabled) { addFixedExposedPort(DEBUG_PORT, DEBUG_PORT) } } - void withDebug() { - withEnv("JAVA_TOOL_OPTIONS", "-agentlib:jdwp=transport=dt_socket,address=*:$DEBUG_PORT,server=y,suspend=n") + private void withDebug() { + def options = [ + envMap.JAVA_TOOL_OPTIONS, + "-agentlib:jdwp=transport=dt_socket,address=*:$DEBUG_PORT,server=y,suspend=n" + ].findAll().join(' ') + withEnv("JAVA_TOOL_OPTIONS", options) } void withConfig(Map config) { - withEnv(normalizeProperties(config)) + withEnv(config.collectEntries { key, value -> + [(normalizeProperty(key)): value] + }) + } + + private static String normalizeProperty(String property) { + property.replace(".", "_") + .replace("[", "_") + .replace("]", "_") } int getPort() { @@ -77,50 +103,38 @@ class PrebidServerContainer extends GenericContainer { getMappedPort(PROMETHEUS_PORT) } + String getDebugAddress() { + debugEnabled ? "$host:${getMappedPort(DEBUG_PORT)}" : null + } + String getInfluxUri() { - return "http://$host:$Dependencies.influxdbContainer.firstMappedPort" + "http://$host:${Dependencies.influxdbContainer.firstMappedPort}" } String getRootUri() { - return "http://$host:$port" + "http://$host:$port" } String getAdminRootUri() { - return "http://$host:$adminPort" + "http://$host:$adminPort" } String getPrometheusRootUri() { - return "http://$host:$prometheusPort" - } - - private static Map normalizeProperties(Map properties) { - properties.collectEntries { [normalizeProperty(it.key), it.value] } as Map - } - - private static String normalizeProperty(String property) { - property.replace(".", "_") - .replace("[", "_") - .replace("]", "_") + "http://$host:$prometheusPort" } PrebidServerContainer withFolder(String containerPath) { - this.withCopyToContainer( + withCopyToContainer( Transferable.of(new byte[0], 010755), - containerPath + "/.keep" + "$containerPath/.keep" ) return this } - // This is a workaround for cases when container is killed mid-test due to OOM void refresh() { if (!running) { stop() start() } } - - @Override - void close() { - super.close() - } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/AccountSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AccountSpec.groovy index e2730e46e52..c98c3f1be30 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AccountSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AccountSpec.groovy @@ -47,9 +47,6 @@ class AccountSpec extends BaseSpec { def logsByTime = pbsService.getLogsByTime(start) assert getLogsByText(logsByTime, warningMessage).size() == 1 - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - where: enforceValidAccount << [true, false] } @@ -84,9 +81,6 @@ class AccountSpec extends BaseSpec { and: "PBs shouldn't emit warning logs" def logsByTime = pbsService.getLogsByTime(start) assert !getLogsByText(logsByTime, warningMessage) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should reject request with unknown account when settings.enforce-valid-account = true"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy index 9013978f76f..034f9c0167c 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AliasSpec.groovy @@ -1,42 +1,61 @@ package org.prebid.server.functional.tests import org.prebid.server.functional.model.bidder.AppNexus +import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.bidder.Openx +import org.prebid.server.functional.model.request.auction.Adrino +import org.prebid.server.functional.model.request.auction.Amx import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.model.request.auction.Targeting +import org.prebid.server.functional.model.response.auction.BidExt +import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST -import static org.prebid.server.functional.model.bidder.BidderName.ALIAS +import static org.prebid.server.functional.model.bidder.BidderName.ALIAS_UPPER_CASE +import static org.prebid.server.functional.model.bidder.BidderName.AMX import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS import static org.prebid.server.functional.model.bidder.BidderName.BOGUS import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.bidder.BidderName.GENER_X import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.CompressionType.GZIP +import static org.prebid.server.functional.model.response.auction.ErrorType.ALIAS import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID import static org.prebid.server.functional.testcontainers.Dependencies.networkServiceContainer import static org.prebid.server.functional.util.HttpUtil.CONTENT_ENCODING_HEADER class AliasSpec extends BaseSpec { - private static final Map ADDITIONAL_BIDDERS_CONFIG = ["adapters.${OPENX.value}.enabled" : "true", - "adapters.${OPENX.value}.endpoint" : "$networkServiceContainer.rootUri/${OPENX.value}/auction".toString(), - "adapters.${APPNEXUS.value}.enabled" : "true", - "adapters.${APPNEXUS.value}.endpoint": "$networkServiceContainer.rootUri/${APPNEXUS.value}/auction".toString()] - private static PrebidServerService pbsServiceWithAdditionalBidders + private static final Map ADDITIONAL_BIDDERS_CONFIG = [ + "adapters.${OPENX.value}.enabled" : "true", + "adapters.${OPENX.value}.endpoint" : "$networkServiceContainer.rootUri/${OPENX.value}/auction".toString(), + "adapters.${APPNEXUS.value}.enabled" : "true", + "adapters.${APPNEXUS.value}.endpoint" : "$networkServiceContainer.rootUri/${APPNEXUS.value}/auction".toString() + ] - def setupSpec() { - pbsServiceWithAdditionalBidders = pbsServiceFactory.getService(ADDITIONAL_BIDDERS_CONFIG + GENERIC_ALIAS_CONFIG) - } + private static final Map AMX_CONFIG = [ + "adapters.amx.enabled" : "true", + "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString() + ] - def cleanupSpec() { - pbsServiceFactory.removeContainer(ADDITIONAL_BIDDERS_CONFIG + GENERIC_ALIAS_CONFIG) - } + private static final Map GENERIC_HARD_ALIAS_CONFIG = + ADDITIONAL_BIDDERS_CONFIG + GENERIC_ALIAS_CONFIG + AMX_CONFIG + + private static final Map AMX_HARD_ALIAS_CONFIG = AMX_CONFIG + [ + "adapters.amx.aliases.alias.enabled" : "true", + "adapters.amx.aliases.alias.meta-info.vendor-id": "0", + "adapters.amx.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), + "adapters.generic.endpoint-compression" : GZIP.value + ] + + private static final PrebidServerService pbsServiceWithGenericHardAlias = pbsServiceFactory.getService(GENERIC_HARD_ALIAS_CONFIG) + private static final PrebidServerService pbsServiceWithAmxHardAlias = pbsServiceFactory.getService(AMX_HARD_ALIAS_CONFIG) - def "PBS should be able to take alias from request"() { + def "PBS should route request-defined alias to its parent adapter"() { given: "Default bid request with alias" def bidRequest = BidRequest.defaultBidRequest.tap { ext.prebid.aliases = [(ALIAS.value): GENERIC] @@ -59,7 +78,7 @@ class AliasSpec extends BaseSpec { assert bidderRequests.size() == 2 } - def "PBS shouldn't apply aliases for bidder when aliases didn't provide proper config"() { + def "PBS should ignore request alias without matching bidder params"() { given: "Default bid request with alias" def bidRequest = BidRequest.defaultBidRequest.tap { ext.prebid.aliases = [(BOGUS.value): GENERIC] @@ -76,27 +95,23 @@ class AliasSpec extends BaseSpec { assert response.ext.debug.resolvedRequest.ext.prebid.aliases == bidRequest.ext.prebid.aliases } - def "PBS should apply compression type for bidder alias when adapters.BIDDER.endpoint-compression = gzip"() { - given: "PBS with adapter configuration" + def "PBS should inherit gzip compression for soft alias"() { + given: "Default bid request with soft alias" def compressionType = GZIP.value - def pbsService = pbsServiceFactory.getService( - ["adapters.generic.endpoint-compression": compressionType]) - - and: "Default bid request with alias" def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.aliases = [(ALIAS.value): GENERIC] - imp[0].ext.prebid.bidder.alias = new Generic() + ext.prebid.aliases = [(GENER_X.value): GENERIC] + imp[0].ext.prebid.bidder.generX = new Generic() } when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithAmxHardAlias.sendAuctionRequest(bidRequest) then: "Bidder request should contain header Content-Encoding = gzip" - assert response.ext?.debug?.httpcalls?.get(ALIAS.value)?.requestHeaders?.first() + assert response.ext?.debug?.httpcalls?.get(GENER_X.value)?.requestHeaders?.first() ?.get(CONTENT_ENCODING_HEADER)?.first() == compressionType } - def "PBS should return an error when GVL Id alias refers to unknown bidder alias"() { + def "PBS should reject alias GVL ID referencing unknown alias"() { given: "Default basic BidRequest with aliasgvlids and aliases" def bidderName = PBSUtils.randomString def validId = 1 @@ -113,7 +128,7 @@ class AliasSpec extends BaseSpec { "vendorId ${validId} refers to unknown bidder alias: ${bidderName.toLowerCase()}") } - def "PBS should return an error when GVL ID alias value is lower that one"() { + def "PBS should reject nonpositive GVL IDs for aliases"() { given: "Default basic BidRequest with aliasgvlids and aliases" def bidderName = PBSUtils.randomString def bidRequest = BidRequest.defaultBidRequest @@ -132,7 +147,7 @@ class AliasSpec extends BaseSpec { invalidId << [PBSUtils.randomNegativeNumber, 0] } - def "PBS should emit error when alias didn't participate in request"() { + def "PBS should reject soft alias referencing unknown parent bidder"() { given: "Default bid request with alias" def randomString = PBSUtils.randomString def bidRequest = BidRequest.defaultBidRequest.tap { @@ -149,27 +164,22 @@ class AliasSpec extends BaseSpec { "refers to unknown bidder: $BOGUS.value" } - def "PBS aliased bidder config should be independently from parent"() { + def "PBS should register configured hard alias independently of parent"() { given: "Default bid request with alias" def bidRequest = BidRequest.defaultBidRequest.tap { imp[0].ext.prebid.bidder.alias = new Generic() } when: "PBS processes auction request" - pbsServiceWithAdditionalBidders.sendAuctionRequest(bidRequest) + pbsServiceWithGenericHardAlias.sendAuctionRequest(bidRequest) then: "Bidder request should contain request per-alies" def bidderRequests = bidder.getBidderRequests(bidRequest.id) assert bidderRequests.size() == 2 } - def "PBS should ignore aliases for requests with a base adapter"() { - given: "PBs server with aliases config" - def pbsConfig = ["adapters.openx.enabled" : "true", - "adapters.openx.endpoint": "$networkServiceContainer.rootUri/openx/auction".toString()] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid request with openx and alias bidder" + def "PBS should prefer a material bidder over a conflicting soft alias"() { + given: "Default bid request with OpenX and request-defined alias" def bidRequest = BidRequest.defaultBidRequest.tap { imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx imp[0].ext.prebid.bidder.generic = new Generic() @@ -177,19 +187,16 @@ class AliasSpec extends BaseSpec { } when: "PBS processes auction request" - def bidResponse = pbsService.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithGenericHardAlias.sendAuctionRequest(bidRequest) then: "PBS contain two http calls and the different url for both" def responseDebug = bidResponse.ext.debug assert responseDebug.httpcalls.size() == 2 assert responseDebug.httpcalls[OPENX.value]*.uri == ["$networkServiceContainer.rootUri/openx/auction"] assert responseDebug.httpcalls[GENERIC.value]*.uri == ["$networkServiceContainer.rootUri/auction"] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } - def "PBS should validate request as alias request and without any warnings when required properties in place"() { + def "PBS should accept valid material bidder params despite conflicting soft alias"() { given: "Default bid request with openx and alias bidder" def bidRequest = BidRequest.defaultBidRequest.tap { imp[0].ext.prebid.bidder.appNexus = AppNexus.default @@ -198,7 +205,7 @@ class AliasSpec extends BaseSpec { } when: "PBS processes auction request" - def bidResponse = pbsServiceWithAdditionalBidders.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithGenericHardAlias.sendAuctionRequest(bidRequest) then: "PBS contain http call for specific bidder" def responseDebug = bidResponse.ext.debug @@ -209,7 +216,7 @@ class AliasSpec extends BaseSpec { assert !bidResponse.ext.warnings } - def "PBS should validate request as alias request and emit proper warnings when validation fails for request"() { + def "PBS should reject invalid material bidder params despite conflicting soft alias"() { given: "Default bid request with openx and alias bidder" def bidRequest = BidRequest.defaultBidRequest.tap { imp[0].ext.prebid.bidder.appNexus = new AppNexus() @@ -218,7 +225,7 @@ class AliasSpec extends BaseSpec { } when: "PBS processes auction request" - def bidResponse = pbsServiceWithAdditionalBidders.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithGenericHardAlias.sendAuctionRequest(bidRequest) then: "PBS shouldn't contain http calls" assert !bidResponse.ext.debug.httpcalls @@ -237,28 +244,27 @@ class AliasSpec extends BaseSpec { "WARNING: request.imp[0].ext must contain at least one valid bidder"] } - def "PBS should invoke as aliases when alias is unknown and core bidder is specified"() { - given: "Default bid request with generic and alias bidder" + def "PBS should invoke both original bidder and request-defined alias"() { + given: "Bid request with original bidder and soft alias" def bidRequest = BidRequest.defaultBidRequest.tap { imp[0].ext.prebid.bidder.generX = new Generic() ext.prebid.aliases = [(GENER_X.value): GENERIC] } when: "PBS processes auction request" - def bidResponse = defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest) - then: "PBS contain two http calls and the same url for both" - def responseDebug = bidResponse.ext.debug - assert responseDebug.httpcalls.size() == 2 - assert responseDebug.httpcalls[GENER_X.value]*.uri == responseDebug.httpcalls[GENERIC.value]*.uri + then: "PBS should send requests to both bidders" + assert response.ext.debug.httpcalls.size() == 2 + assert response.ext.debug.httpcalls[GENER_X.value]*.uri == ["$networkServiceContainer.rootUri/auction"] + assert response.ext.debug.httpcalls[GENERIC.value]*.uri == ["$networkServiceContainer.rootUri/auction"] - and: "Bidder request should contain request per-alies" - def bidderRequests = bidder.getBidderRequests(bidRequest.id) - assert bidderRequests.size() == 2 + and: "Bidder should receive two requests" + assert bidder.getBidderRequests(bidRequest.id).size() == 2 } - def "PBS should invoke aliases when alias is unknown and no core bidder is specified"() { - given: "Default bid request with generic and alias bidder" + def "PBS should invoke only request-defined alias when original bidder is absent"() { + given: "Bid request with soft alias and without original bidder" def bidRequest = BidRequest.defaultBidRequest.tap { imp[0].ext.prebid.bidder.generX = new Generic() imp[0].ext.prebid.bidder.generic = null @@ -266,11 +272,287 @@ class AliasSpec extends BaseSpec { } when: "PBS processes auction request" - def bidResponse = defaultPbsService.sendAuctionRequest(bidRequest) + def response = defaultPbsService.sendAuctionRequest(bidRequest) - then: "PBS contain two http calls and the same url for both" - def responseDebug = bidResponse.ext.debug - assert responseDebug.httpcalls.size() == 1 - assert responseDebug.httpcalls[GENER_X.value] + then: "PBS should send request only to alias" + assert response.ext.debug.httpcalls.size() == 1 + assert response.ext.debug.httpcalls[GENER_X.value]*.uri == ["$networkServiceContainer.rootUri/auction"] + + and: "Bidder should receive one request" + assert bidder.getBidderRequests(bidRequest.id).size() == 1 + } + + def "PBS should preserve uppercase soft alias in seat and targeting"() { + given: "Default bid request with alias" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.aliases = [(ALIAS.value): GENERIC] + ext.prebid.targeting = new Targeting() + imp[0].ext.prebid.bidder.tap { + generic = null + aliasUpperCase = new Generic() + } + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [ALIAS_UPPER_CASE] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${ALIAS_UPPER_CASE}"] + assert targeting["hb_size_${ALIAS_UPPER_CASE}"] + assert targeting["hb_bidder"] == ALIAS_UPPER_CASE.value + assert targeting["hb_bidder_${ALIAS_UPPER_CASE}"] == ALIAS_UPPER_CASE.value + + and: "Response should contain repose millis with corresponding bidder" + assert response.ext.responsetimemillis.containsKey(ALIAS_UPPER_CASE.value) + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + + def "PBS should reject invalid bidder parameters for generic and hard alias"() { + given: "Default basic generic BidRequest" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.tap { + it.generic.exampleProperty = PBSUtils.randomNumber + //Adrino hard coded bidder alias in generic.yaml + it.adrino = new Adrino(hash: PBSUtils.randomNumber) + } + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder should be dropped" + assert response.ext?.warnings[PREBID]*.code == [999, 999, 999] + assert response.ext?.warnings[PREBID]*.message == + ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + + "\$.exampleProperty: integer found, string expected", + "WARNING: request.imp[0].ext.prebid.bidder.adrino was dropped with a reason: " + + "request.imp[0].ext.prebid.bidder.adrino failed validation.\n" + + "\$.hash: integer found, string expected", + "WARNING: request.imp[0].ext must contain at least one valid bidder"] + + and: "PBS should not call bidder" + assert bidder.getRequestCount(bidRequest.id) == 0 + + and: "targeting should be empty" + assert response.seatbid.isEmpty() + } + + def "PBS should retain parent adapter code for soft alias"() { + given: "Default bid request with alias" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.tap { + generic = null + alias = new Generic() + } + ext.prebid.aliases = [(ALIAS.value): GENERIC] + ext.prebid.targeting = new Targeting() + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [GENERIC] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value + + and: "Response should contain repose millis with corresponding bidder" + assert response.ext.responsetimemillis.containsKey(ALIAS.value) + + and: "Bidder request should be valid and not contain aliases" + def bidderRequests = bidder.getBidderRequests(bidRequest.id).first + assert !bidderRequests.ext.prebid.aliases + } + + def "PBS should use alias adapter code for Generic hard alias"() { + given: "Default bid request with hard alias" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.tap { + generic = null + alias = new Generic() + } + ext.prebid.targeting = new Targeting() + } + + when: "PBS processes auction request" + def response = pbsServiceWithGenericHardAlias.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value + + and: "Response should contain repose millis with corresponding bidder" + assert response.ext.responsetimemillis.containsKey(ALIAS.value) + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + + def "PBS should propagate demandSource for AMX hard alias"() { + given: "Default bid request with AMX hard alias" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.tap { + generic = null + alias = new Generic() + } + ext.prebid.targeting = new Targeting() + } + + and: "Bid response with bidder code" + def demandSource = PBSUtils.randomString + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, BidderName.ALIAS).tap { + it.seatbid[0].bid[0].ext = new BidExt(demandSource: demandSource) + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsServiceWithAmxHardAlias.sendAuctionRequest(bidRequest) + + then: "Response should contain demand source" + assert response.seatbid.bid.ext.prebid.meta.demandSource.flatten() == [demandSource] + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value + + and: "Response should contain repose millis with corresponding bidder" + assert response.ext.responsetimemillis.containsKey(ALIAS.value) + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + + def "PBS should prefer AMX hard alias over conflicting soft alias"() { + given: "Bid request with AMX hard alias and conflicting soft alias" + def bidRequest = BidRequest.getDefaultBidRequest().tap { + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.amx = null + imp[0].ext.prebid.bidder.generic = null + it.ext.prebid.aliases = [(ALIAS.value): GENERIC] + it.ext.prebid.targeting = new Targeting() + } + + when: "PBS processes auction request" + def response = pbsServiceWithAmxHardAlias.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value + + and: "Response should contain repose millis with corresponding bidder" + assert response.ext.responsetimemillis.containsKey(ALIAS.value) + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + + def "PBS should prefer Generic hard alias over conflicting soft alias"() { + given: "Bid request with Generic hard alias and conflicting soft alias" + def bidRequest = BidRequest.getDefaultBidRequest().tap { + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.amx = null + imp[0].ext.prebid.bidder.generic = null + it.ext.prebid.aliases = [(ALIAS.value): AMX] + it.ext.prebid.targeting = new Targeting() + } + + when: "PBS processes auction request" + def response = pbsServiceWithGenericHardAlias.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] + + and: "Response should contain seat bid" + assert response.seatbid.seat == [BidderName.ALIAS] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${BidderName.ALIAS}"] + assert targeting["hb_size_${BidderName.ALIAS}"] + assert targeting["hb_bidder"] == BidderName.ALIAS.value + assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value + + and: "Response should contain repose millis with corresponding bidder" + assert response.ext.responsetimemillis.containsKey(ALIAS.value) + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) + } + + def "PBS should preserve material AMX bidder despite conflicting soft alias"() { + given: "Bid request with AMX material bidder and conflicting soft alias" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.amx = new Amx() + imp[0].ext.prebid.bidder.generic = null + ext.prebid.targeting = new Targeting() + ext.prebid.aliases = [(AMX.value): GENERIC] + } + + when: "PBS processes auction request" + def response = pbsServiceWithGenericHardAlias.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] + + and: "Response should contain seat" + assert response.seatbid.seat == [AMX] + + and: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${AMX}"] + assert targeting["hb_size_${AMX}"] + assert targeting["hb_bidder"] == AMX.value + assert targeting["hb_bidder_${AMX}"] == AMX.value + + and: "Response should contain repose millis with corresponding bidder" + assert response.ext.responsetimemillis.containsKey(AMX.value) + + and: "Bidder request should be valid" + assert bidder.getBidderRequests(bidRequest.id) } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy index 27bc35f3cc3..51b19f9ebfe 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AlternateBidderCodeSpec.groovy @@ -18,6 +18,7 @@ import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.util.PBSUtils import spock.lang.Shared @@ -41,8 +42,8 @@ class AlternateBidderCodeSpec extends BaseSpec { private static final String ERROR_BID_CODE_VALIDATION = "BidId `%s` validation messages: " + "Error: invalid bidder code %s was set by the adapter %s for the account %s" private static final String INVALID_BIDDER_CODE_LOGS = "invalid bidder code %s was set by the adapter %s for the account %s" - private static final Map AMX_CONFIG = ["adapters.amx.enabled" : "true", - "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + private static final PbsContainerConfig AMX_CONFIG = new PbsContainerConfig(["adapters.amx.enabled" : "true", + "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString()]) @Shared private static final PrebidServerService pbsServiceWithAmxBidder = pbsServiceFactory.getService(AMX_CONFIG) @@ -1159,9 +1160,6 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Alert.general metric shouldn't be updated" def metrics = pbsService.sendCollectedMetricsRequest() assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(AMX)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(config) } def "PBS should discard the bid and emit a response warning when request alternate bidder codes are enabled and the allowed bidder codes doesn't match the bidder's request"() { @@ -1330,9 +1328,6 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "Bidder request should be valid" assert bidder.getBidderRequests(bidRequest.id) - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - where: allowedBidderCodes << [BOGUS, UNKNOWN] } @@ -1387,9 +1382,6 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBS shouldn't emit validation metrics" def metrics = defaultPbsService.sendCollectedMetricsRequest() assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(GENERIC)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS shouldn't discard bid when alternate bidder code allow and soft alias with case"() { @@ -1574,9 +1566,6 @@ class AlternateBidderCodeSpec extends BaseSpec { and: "PBS shouldn't emit validation metrics" def metrics = defaultPbsService.sendCollectedMetricsRequest() assert !metrics[ADAPTER_RESPONSE_VALIDATION_METRICS.formatted(GENERIC)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should populate two seat bid when different bidder response with same seat"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/AuctionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AuctionSpec.groovy index 166f49e4cf6..0053ba0a3ba 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AuctionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AuctionSpec.groovy @@ -12,9 +12,6 @@ import org.prebid.server.functional.model.request.auction.Device import org.prebid.server.functional.model.request.auction.DeviceExt import org.prebid.server.functional.model.request.auction.Imp import org.prebid.server.functional.model.request.auction.PrebidStoredRequest -import org.prebid.server.functional.model.request.auction.Renderer -import org.prebid.server.functional.model.request.auction.RendererData -import org.prebid.server.functional.model.request.auction.Sdk import org.prebid.server.functional.model.request.auction.User import org.prebid.server.functional.model.request.auction.UserExt import org.prebid.server.functional.model.request.auction.UserExtPrebid @@ -27,7 +24,6 @@ import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.HttpUtil import org.prebid.server.functional.util.PBSUtils -import spock.lang.Shared import static org.prebid.server.functional.model.AccountStatus.ACTIVE import static org.prebid.server.functional.model.AccountStatus.INACTIVE @@ -49,17 +45,20 @@ class AuctionSpec extends BaseSpec { private static final Integer DEFAULT_TIMEOUT = getRandomTimeout() private static final Integer MIN_BID_ID_LENGTH = 17 private static final Integer DEFAULT_UUID_LENGTH = 36 - private static final Map GENERIC_CONFIG = [ - "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : USER_SYNC_URL] - @Shared - PrebidServerService prebidServerService = pbsServiceFactory.getService(PBS_CONFIG) - + private static final String GENERIC_COOKIE_NAME = PBSUtils.randomString private static final String IMPS_REQUESTED_METRIC = 'imps_requested' private static final String IMPS_DROPPED_METRIC = 'imps_dropped' private static final Integer IMP_LIMIT = 1 + + private static final Map GENERIC_CONFIG = [ + "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : USER_SYNC_URL] private static final Map PBS_CONFIG = ["auction.biddertmax.max" : MAX_TIMEOUT as String, + "host-cookie.family" : GENERIC.value, + "host-cookie.cookie-name" : GENERIC_COOKIE_NAME, "auction.default-timeout-ms": DEFAULT_TIMEOUT as String] + private static final PrebidServerService prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + GENERIC_CONFIG) + def "PBS should return version in response header for auction request for #description"() { when: "PBS processes auction request" def response = defaultPbsService.sendAuctionRequestRaw(bidRequest) @@ -68,9 +67,9 @@ class AuctionSpec extends BaseSpec { assert response.headers["x-prebid"] == ["pbs-java/$PBS_VERSION"] where: - bidRequest || description - BidRequest.defaultBidRequest || "valid bid request" - new BidRequest() || "invalid bid request" + bidRequest | description + BidRequest.defaultBidRequest | "valid bid request" + new BidRequest() | "invalid bid request" } def "PBS should update account..requests.rejected.invalid-account metric when account is inactive"() { @@ -159,11 +158,7 @@ class AuctionSpec extends BaseSpec { } def "PBS should populate buyeruid from uids cookie when buyeruids with appropriate bidder but without value present in request"() { - given: "PBS config" - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG - + ["adapters.${GENERIC.value}.usersync.${REDIRECT.value}.url" : USER_SYNC_URL]) - - and: "Bid request with buyeruids" + given: "Bid request with buyeruids" def bidRequest = BidRequest.defaultBidRequest.tap { user = new User(ext: new UserExt(prebid: new UserExtPrebid(buyeruids: [(GENERIC): ""]))) } @@ -181,11 +176,7 @@ class AuctionSpec extends BaseSpec { } def "PBS shouldn't populate buyeruid from uids cookie when buyeruids with appropriate bidder but without value present in request"() { - given: "PBS config" - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG - + ["adapters.${GENERIC.value}.usersync.${REDIRECT.value}.url" : USER_SYNC_URL]) - - and: "Bid request with buyeruids" + given: "Bid request with buyeruids" def bidRequest = BidRequest.defaultBidRequest.tap { user = new User(ext: new UserExt(prebid: new UserExtPrebid(buyeruids: [(GENERIC): ""]))) } @@ -221,19 +212,12 @@ class AuctionSpec extends BaseSpec { } def "PBS should populate buyeruid from host cookie name config when host cookie family matched with requested bidder"() { - given: "PBS config" - def cookieName = PBSUtils.randomString - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + GENERIC_CONFIG - + ["host-cookie.family" : GENERIC.value, - "host-cookie.cookie-name" : cookieName, - "adapters.generic.usersync.cookie-family-name": GENERIC.value]) - - and: "Bid request" + given: "Bid request" def bidRequest = BidRequest.defaultBidRequest and: "Host cookie" def hostCookieUid = UUID.randomUUID().toString() - def cookies = HttpUtil.getCookieHeader(cookieName, hostCookieUid) + def cookies = HttpUtil.getCookieHeader(GENERIC_COOKIE_NAME, hostCookieUid) when: "PBS processes auction request" prebidServerService.sendAuctionRequest(bidRequest, cookies) @@ -267,13 +251,7 @@ class AuctionSpec extends BaseSpec { } def "PBS shouldn't populate buyeruid from cookie when cookie-name in cookie and config are diferent"() { - given: "PBS config" - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + GENERIC_CONFIG - + ["host-cookie.family" : GENERIC.value, - "host-cookie.cookie-name" : PBSUtils.randomString, - "adapters.generic.usersync.cookie-family-name": GENERIC.value]) - - and: "Bid request" + given: "Bid request" def bidRequest = BidRequest.defaultBidRequest and: "Host cookie" @@ -335,14 +313,7 @@ class AuctionSpec extends BaseSpec { } def "PBS call to alias should populate bidder request buyeruid from family user.buyeruids when resolved name is present"() { - given: "Pbs config with alias" - def cookieName = PBSUtils.randomString - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + GENERIC_CONFIG - + ["host-cookie.family" : GENERIC.value, - "host-cookie.cookie-name" : cookieName, - "adapters.generic.usersync.cookie-family-name": GENERIC.value]) - - and: "Alias bid request" + given: "Alias bid request" def buyeruid = PBSUtils.randomString def bidRequest = BidRequest.defaultBidRequest.tap { imp[0].ext.prebid.bidder.alias = new Generic() @@ -353,7 +324,7 @@ class AuctionSpec extends BaseSpec { and: "Host cookie" def hostCookieUid = UUID.randomUUID().toString() - def cookies = HttpUtil.getCookieHeader(cookieName, hostCookieUid) + def cookies = HttpUtil.getCookieHeader(GENERIC_COOKIE_NAME, hostCookieUid) when: "PBS processes auction request" prebidServerService.sendAuctionRequest(bidRequest, cookies) @@ -590,14 +561,11 @@ class AuctionSpec extends BaseSpec { and: "BidResponse should contain generated UUID" assert PBSUtils.isUUID(response.seatbid.first.bid.first.id) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } - def "PBS shouldn't override short bid.id when enforce-random-bid-id in default or disabled"() { - given: "PBS with disabled generate-bid-id" - def pbsConfig = ["auction.enforce-random-bid-id": enforceRandomBidId] + def "PBS shouldn't override long enough bid.id with random uuid when enforce-random-bid-id is enabled"() { + given: "PBS with enabled generate-bid-id" + def pbsConfig = ['auction.enforce-random-bid-id': 'true'] def pbsService = pbsServiceFactory.getService(pbsConfig) and: "Default bid request" @@ -606,7 +574,7 @@ class AuctionSpec extends BaseSpec { } and: "Default bid response" - def originalBidId = PBSUtils.getRandomString(PBSUtils.getRandomNumber(1, MIN_BID_ID_LENGTH)) + def originalBidId = PBSUtils.getRandomString(PBSUtils.getRandomNumber(MIN_BID_ID_LENGTH, DEFAULT_UUID_LENGTH)) def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { seatbid.first.bid.first.id = originalBidId } @@ -630,17 +598,11 @@ class AuctionSpec extends BaseSpec { and: "BidResponse should contain original bid.id" assert response.seatbid.bid.id.flatten().sort() == [originalBidId] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - - where: - enforceRandomBidId << [null, 'false'] } - def "PBS shouldn't override long enough bid.id with random uuid when enforce-random-bid-id is enabled"() { - given: "PBS with enabled generate-bid-id" - def pbsConfig = ['auction.enforce-random-bid-id': 'true'] + def "PBS shouldn't override short bid.id when enforce-random-bid-id in default or disabled"() { + given: "PBS with disabled generate-bid-id" + def pbsConfig = ["auction.enforce-random-bid-id": enforceRandomBidId] def pbsService = pbsServiceFactory.getService(pbsConfig) and: "Default bid request" @@ -649,7 +611,7 @@ class AuctionSpec extends BaseSpec { } and: "Default bid response" - def originalBidId = PBSUtils.getRandomString(PBSUtils.getRandomNumber(MIN_BID_ID_LENGTH, DEFAULT_UUID_LENGTH)) + def originalBidId = PBSUtils.getRandomString(PBSUtils.getRandomNumber(1, MIN_BID_ID_LENGTH)) def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { seatbid.first.bid.first.id = originalBidId } @@ -674,8 +636,8 @@ class AuctionSpec extends BaseSpec { and: "BidResponse should contain original bid.id" assert response.seatbid.bid.id.flatten().sort() == [originalBidId] - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) + where: + enforceRandomBidId << [null, 'false'] } def "PBS should drop extra impressions with warnings when number of impressions exceeds impression-limit"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/BaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BaseSpec.groovy index b50f9772eef..567a7a76382 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BaseSpec.groovy @@ -14,6 +14,7 @@ import org.prebid.server.functional.repository.dao.StoredResponseDao import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.Dependencies import org.prebid.server.functional.testcontainers.PbsServiceFactory +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.testcontainers.scaffolding.Bidder import org.prebid.server.functional.testcontainers.scaffolding.PrebidCache import org.prebid.server.functional.testcontainers.scaffolding.VendorList @@ -27,11 +28,12 @@ import static java.math.RoundingMode.DOWN import static java.math.RoundingMode.HALF_UP import static java.math.RoundingMode.UP import static org.prebid.server.functional.testcontainers.Dependencies.networkServiceContainer +import static org.prebid.server.functional.testcontainers.PbsServiceFactory.ContainerPolicy.PERSISTENT import static org.prebid.server.functional.util.SystemProperties.DEFAULT_TIMEOUT abstract class BaseSpec extends Specification implements ObjectMapperWrapper { - protected static final PbsServiceFactory pbsServiceFactory = new PbsServiceFactory(networkServiceContainer) + protected static final PbsServiceFactory pbsServiceFactory = new PbsServiceFactory() protected static final Bidder bidder = new Bidder(networkServiceContainer) protected static final VendorList vendorList = new VendorList(networkServiceContainer) protected static final PrebidCache prebidCache = new PrebidCache(networkServiceContainer) @@ -50,8 +52,12 @@ abstract class BaseSpec extends Specification implements ObjectMapperWrapper { protected static final Map GENERIC_ALIAS_CONFIG = ["adapters.generic.aliases.alias.enabled" : "true", "adapters.generic.aliases.alias.meta-info.vendor-id": "0", "adapters.generic.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString()] + protected static final Map EMPTY_CACHE_TTL_CONFIG = ["cache.default-ttl-seconds.banner": "", + "cache.default-ttl-seconds.video" : "", + "cache.default-ttl-seconds.native": "", + "cache.default-ttl-seconds.audio" : ""] - protected static final PrebidServerService defaultPbsService = pbsServiceFactory.getService([:]) + protected static final PrebidServerService defaultPbsService = pbsServiceFactory.getService(new PbsContainerConfig(), PERSISTENT) def setupSpec() { prebidCache.setResponse() diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy index 2c8837301bc..ba6be655c44 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidAdjustmentSpec.groovy @@ -21,6 +21,7 @@ import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.PbsConfig +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.testcontainers.scaffolding.CurrencyConversion import org.prebid.server.functional.util.CurrencyUtil import org.prebid.server.functional.util.PBSUtils @@ -66,16 +67,17 @@ class BidAdjustmentSpec extends BaseSpec { private static final CurrencyConversion currencyConversion = new CurrencyConversion(networkServiceContainer) private static final Map AMX_CONFIG = ["adapters.amx.enabled" : "true", "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + private static final PbsContainerConfig CURRENCY_CONFIG = new PbsContainerConfig(PbsConfig.currencyConverterConfig + AMX_CONFIG) private static PrebidServerService pbsService def setupSpec() { currencyConversion.setCurrencyConversionRatesResponse() - pbsService = pbsServiceFactory.getService(PbsConfig.currencyConverterConfig + AMX_CONFIG) + pbsService = pbsServiceFactory.getService(CURRENCY_CONFIG) } @Override def cleanupSpec() { - pbsServiceFactory.removeContainer(PbsConfig.currencyConverterConfig + AMX_CONFIG) + pbsServiceFactory.removeContainer(CURRENCY_CONFIG) } def "PBS should adjust bid price for matching bidder when request has per-bidder bid adjustment factors"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidExpResponseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidExpResponseSpec.groovy index 6ca55f4b7bc..8b0bc676a8d 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidExpResponseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidExpResponseSpec.groovy @@ -633,9 +633,6 @@ class BidExpResponseSpec extends BaseSpec { then: "Bid response should contain exp data" assert response.seatbid.first.bid.first.exp == bidExpValue - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(config) - where: mediaType | bidExpValue BANNER | BANNER_TTL_DEFAULT_CACHE diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy deleted file mode 100644 index 49bbd9c2e17..00000000000 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ /dev/null @@ -1,1719 +0,0 @@ -package org.prebid.server.functional.tests - -import org.prebid.server.functional.model.bidder.AppNexus -import org.prebid.server.functional.model.bidder.BidderName -import org.prebid.server.functional.model.bidder.Generic -import org.prebid.server.functional.model.config.Endpoint -import org.prebid.server.functional.model.db.Account -import org.prebid.server.functional.model.db.StoredImp -import org.prebid.server.functional.model.db.StoredRequest -import org.prebid.server.functional.model.request.amp.AmpRequest -import org.prebid.server.functional.model.request.auction.Adrino -import org.prebid.server.functional.model.request.auction.Amx -import org.prebid.server.functional.model.request.auction.Banner -import org.prebid.server.functional.model.request.auction.BidRequest -import org.prebid.server.functional.model.request.auction.Device -import org.prebid.server.functional.model.request.auction.AnyUnsupportedBidder -import org.prebid.server.functional.model.request.auction.Geo -import org.prebid.server.functional.model.request.auction.Imp -import org.prebid.server.functional.model.request.auction.ImpExt -import org.prebid.server.functional.model.request.auction.ImpExtContext -import org.prebid.server.functional.model.request.auction.ImpExtContextData -import org.prebid.server.functional.model.request.auction.Native -import org.prebid.server.functional.model.request.auction.PrebidOptions -import org.prebid.server.functional.model.request.auction.PrebidStoredRequest -import org.prebid.server.functional.model.request.auction.Site -import org.prebid.server.functional.model.request.auction.Source -import org.prebid.server.functional.model.request.auction.Targeting -import org.prebid.server.functional.model.request.vtrack.VtrackRequest -import org.prebid.server.functional.model.request.vtrack.xml.Vast -import org.prebid.server.functional.model.response.auction.Adm -import org.prebid.server.functional.model.response.auction.Bid -import org.prebid.server.functional.model.response.auction.BidExt -import org.prebid.server.functional.model.response.auction.BidResponse -import org.prebid.server.functional.util.PBSUtils -import org.prebid.server.functional.util.privacy.CcpaConsent - -import static org.prebid.server.functional.model.Currency.CHF -import static org.prebid.server.functional.model.Currency.EUR -import static org.prebid.server.functional.model.Currency.JPY -import static org.prebid.server.functional.model.Currency.USD -import static org.prebid.server.functional.model.bidder.BidderName.ALIAS_UPPER_CASE -import static org.prebid.server.functional.model.bidder.BidderName.AMX -import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS -import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE -import static org.prebid.server.functional.model.bidder.BidderName.OPENX -import static org.prebid.server.functional.model.bidder.CompressionType.GZIP -import static org.prebid.server.functional.model.bidder.CompressionType.NONE -import static org.prebid.server.functional.model.request.auction.Asset.titleAsset -import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP -import static org.prebid.server.functional.model.request.auction.DistributionChannel.DOOH -import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE -import static org.prebid.server.functional.model.request.auction.SecurityLevel.NON_SECURE -import static org.prebid.server.functional.model.request.auction.SecurityLevel.SECURE -import static org.prebid.server.functional.model.response.auction.BidRejectionReason.REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY -import static org.prebid.server.functional.model.response.auction.ErrorType.ALIAS -import static org.prebid.server.functional.model.response.auction.ErrorType.GENERIC -import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID -import static org.prebid.server.functional.model.response.auction.MediaType.AUDIO -import static org.prebid.server.functional.model.response.auction.MediaType.BANNER -import static org.prebid.server.functional.model.response.auction.MediaType.NATIVE -import static org.prebid.server.functional.model.response.auction.MediaType.VIDEO -import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer -import static org.prebid.server.functional.util.HttpUtil.CONTENT_ENCODING_HEADER -import static org.prebid.server.functional.util.privacy.CcpaConsent.Signal.ENFORCED - -class BidderParamsSpec extends BaseSpec { - - private static final Map DISABLE_INVALID_BIDDER_CONFIGS = [ - "adapters.audiencenetwork.enabled": "false", - "adapters.adxcg.enabled" : "false", - "adapters.avocet.enabled" : "false", - "adapters.pangle.enabled" : "false", - "adapters.teqblaze.enabled" : "false", - "adapters.ix.enabled" : "false" - ] - - def "PBS should send request to bidder when adapter-defaults.enabled = #adapterDefault and adapters.BIDDER.enabled = #generic"() { - given: "PBS with adapter configuration" - def pbsService = pbsServiceFactory.getService(adapterConfig) - - and: "Default basic generic BidRequest" - def bidRequest = BidRequest.defaultBidRequest - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain httpcalls" - assert response.ext?.debug?.httpcalls[BidderName.GENERIC.value] - - and: "Response should not contain error" - assert !response.ext?.errors - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(adapterConfig) - - where: - adapterDefault | generic | adapterConfig - "true" | "true" | ["adapter-defaults.enabled": adapterDefault, - "adapters.generic.enabled": generic] + DISABLE_INVALID_BIDDER_CONFIGS - - "false" | "true" | ["adapter-defaults.enabled": adapterDefault, - "adapters.generic.enabled": generic] - } - - def "PBS should not send request to bidder and emit error when adapter-defaults.enabled = #adapterDefault and adapters.BIDDER.enabled = #generic"() { - given: "PBS with adapter configuration" - def pbsService = pbsServiceFactory.getService(adapterConfig) - - and: "Default basic generic BidRequest" - def bidRequest = BidRequest.defaultBidRequest - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain error" - assert response.ext?.errors[GENERIC]*.code == [2] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(adapterConfig) - - where: - adapterDefault | generic | adapterConfig - "false" | "false" | ["adapter-defaults.enabled": adapterDefault, - "adapters.generic.enabled": generic] - "true" | "false" | ["adapter-defaults.enabled": adapterDefault, - "adapters.generic.enabled": generic] + DISABLE_INVALID_BIDDER_CONFIGS - } - - def "PBS should modify vast xml when adapter-defaults.modifying-vast-xml-allowed = #adapterDefault and BIDDER.modifying-vast-xml-allowed = #generic"() { - given: "PBS with adapter configuration" - def pbsConfig = ["adapter-defaults.modifying-vast-xml-allowed": adapterDefault, - "adapters.generic.modifying-vast-xml-allowed": generic] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default vtrack request" - String payload = PBSUtils.randomString - def request = VtrackRequest.getDefaultVtrackRequest(encodeXml(Vast.getDefaultVastModel(payload))) - def accountId = PBSUtils.randomNumber - - and: "Account in the DB" - def account = new Account(uuid: accountId, eventsEnabled: true) - accountDao.save(account) - - when: "PBS processes vtrack request" - pbsService.sendPostVtrackRequest(request, accountId.toString()) - - then: "vast xml is modified" - def prebidCacheRequest = prebidCache.getXmlRecordedRequestsBody(payload) - assert prebidCacheRequest.size() == 1 - assert prebidCacheRequest.first().contains("${Endpoint.EVENT}?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}") - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - - where: - adapterDefault | generic - "true" | "true" - "false" | "true" - } - - def "PBS should not modify vast xml when adapter-defaults.modifying-vast-xml-allowed = #adapterDefault and BIDDER.modifying-vast-xml-allowed = #generic"() { - given: "PBS with adapter configuration" - def pbsConfig = ["adapter-defaults.modifying-vast-xml-allowed": adapterDefault, - "adapters.generic.modifying-vast-xml-allowed": generic] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default VtrackRequest" - String payload = PBSUtils.randomString - def request = VtrackRequest.getDefaultVtrackRequest(encodeXml(Vast.getDefaultVastModel(payload))) - def accountId = PBSUtils.randomNumber - - and: "Account in the DB" - def account = new Account(uuid: accountId, eventsEnabled: true) - accountDao.save(account) - - when: "PBS processes vtrack request" - pbsService.sendPostVtrackRequest(request, accountId.toString()) - - then: "vast xml is not modified" - def prebidCacheRequest = prebidCache.getXmlRecordedRequestsBody(payload) - assert prebidCacheRequest.size() == 1 - assert !prebidCacheRequest.first().contains("${Endpoint.EVENT}?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}") - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - - where: - adapterDefault | generic - "true" | "false" - "false" | "false" - } - - def "PBS should mask values when adapter-defaults.pbs-enforces-ccpa = #adapterDefault settings when BIDDER.pbs-enforces-ccpa = #generic"() { - given: "PBS with adapter configuration" - def pbsConfig = ["adapter-defaults.pbs-enforces-ccpa": adapterDefault, - "adapters.generic.pbs-enforces-ccpa": generic] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic generic BidRequest" - def bidRequest = BidRequest.defaultBidRequest - def validCcpa = new CcpaConsent(explicitNotice: ENFORCED, optOutSale: ENFORCED) - bidRequest.regs.usPrivacy = validCcpa - def lat = PBSUtils.getRandomDecimal(0, 90) - def lon = PBSUtils.getRandomDecimal(0, 90) - bidRequest.device = new Device(geo: new Geo(lat: lat, lon: lon)) - - when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) - - then: "Bidder request should contain masked values" - def bidderRequests = bidder.getBidderRequest(bidRequest.id) - assert bidderRequests.device?.geo?.lat as BigDecimal == PBSUtils.roundDecimal(lat, 2) - assert bidderRequests.device?.geo?.lon as BigDecimal == PBSUtils.roundDecimal(lon, 2) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - - where: - adapterDefault | generic - "true" | "true" - "false" | "true" - } - - def "PBS should not mask values when adapter-defaults.pbs-enforces-ccpa = #adapterDefault settings when BIDDER.pbs-enforces-ccpa = #generic"() { - given: "PBS with adapter configuration" - def pbsConfig = ["adapter-defaults.pbs-enforces-ccpa": adapterDefault, - "adapters.generic.pbs-enforces-ccpa": generic] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic generic BidRequest" - def bidRequest = BidRequest.defaultBidRequest - def validCcpa = new CcpaConsent(explicitNotice: ENFORCED, optOutSale: ENFORCED) - bidRequest.regs.usPrivacy = validCcpa - def lat = PBSUtils.getRandomDecimal(0, 90) as float - def lon = PBSUtils.getRandomDecimal(0, 90) as float - bidRequest.device = new Device(geo: new Geo(lat: lat, lon: lon)) - - when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) - - then: "Bidder request should contain not masked values" - def bidderRequests = bidder.getBidderRequest(bidRequest.id) - assert bidderRequests.device?.geo?.lat == lat - assert bidderRequests.device?.geo?.lon == lon - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - - where: - adapterDefault | generic - "true" | "false" - "false" | "false" - } - - def "PBS should prefer bidder params from imp[*].ext.prebid.bidder.BIDDER when ext.prebid.bidderparams.BIDDER is specified"() { - given: "Default basic BidRequest" - def bidRequest = BidRequest.defaultBidRequest - def firstParam = PBSUtils.randomNumber - bidRequest.imp.first().ext.prebid.bidder.generic = new Generic(firstParam: firstParam) - - and: "Set bidderParam to bidRequest" - bidRequest.ext.prebid.bidderParams = [(BidderName.GENERIC): [firstParam: PBSUtils.randomNumber]] - - when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Bidder request should contain zoneId value from imp[*].ext.prebid.bidder.BIDDER" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp[0]?.ext?.bidder?.firstParam == firstParam - - and: "Bidder request should contain requested bidder param for related itself bidder" - assert bidderRequest.ext.prebid.bidderParams[GENERIC] == bidRequest.ext.prebid.bidderParams[GENERIC] - } - - def "PBS should send bidder params from imp[*].ext.prebid.bidder.BIDDER when ext.prebid.bidderparams.BIDDER isn't specified"() { - given: "Default basic BidRequest" - def bidRequest = BidRequest.defaultBidRequest - def firstParam = PBSUtils.randomNumber - bidRequest.imp.first().ext.prebid.bidder.generic = new Generic(firstParam: firstParam) - - and: "Set bidderParam = null to bidRequest" - bidRequest.ext.prebid.bidderParams = null - - when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain zoneId value from imp[*].ext.prebid.bidder.BIDDER" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp[0]?.ext?.bidder?.firstParam == firstParam - } - - def "PBS should merge bidder params from imp[*].ext.prebid.bidder.BIDDER and ext.prebid.bidderparams.BIDDER"() { - given: "Default basic BidRequest with zoneId = null" - def bidRequest = BidRequest.defaultBidRequest - def firstParam = PBSUtils.randomNumber - bidRequest.imp.first().ext.prebid.bidder.generic = new Generic(firstParam: firstParam) - - and: "Set bidderParam to bidRequest" - def secondParam = PBSUtils.randomNumber - bidRequest.ext.prebid.bidderParams = [(BidderName.GENERIC): [secondParam: secondParam]] - - when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should merge bidder params" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp[0]?.ext?.bidder?.firstParam == firstParam - assert bidderRequest.imp[0]?.ext?.bidder?.secondParam == secondParam - } - - def "PBS should only send bidder params from ext.prebid.bidderparams.BIDDER to specified bidder"() { - given: "Default basic BidRequest" - def bidRequest = BidRequest.defaultBidRequest - def firstParam = PBSUtils.randomNumber - bidRequest.imp.first().ext.prebid.bidder.generic = new Generic(firstParam: firstParam) - bidRequest.imp.first().ext.prebid.bidder.appNexus = null - - and: "Set bidderParam to bidRequest" - bidRequest.ext.prebid.bidderParams = [(APPNEXUS): [placement_id: PBSUtils.randomNumber]] - - when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response shouldn't contain bidder param from another bidder" - bidder.getBidderRequest(bidRequest.id) - } - - def "PBS should reject bidder when bidder params from request doesn't satisfy json-schema for auction request"() { - given: "BidRequest with bad bidder datatype" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp << Imp.defaultImpression - imp[0].ext.prebid.bidder.generic.exampleProperty = PBSUtils.randomNumber - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "PBS should not fail the entire auction" - assert response.seatbid[0].bid.size() == 1 - - and: "PBS should call bidder" - assert bidder.getRequestCount(bidRequest.id) == 1 - - and: "Bidder with invalid params should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999] - assert response.ext?.warnings[PREBID]*.message == - ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + - "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + - "\$.exampleProperty: integer found, string expected", - "WARNING: request.imp[0].ext must contain at least one valid bidder"] - } - - def "PBS should reject bidder when bidder params from stored request doesn't satisfy json-schema for auction request"() { - given: "BidRequest with stored request, without imp" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomNumber) - imp = null - } - - and: "Default stored request with bad bidder datatype" - def storedRequestModel = BidRequest.defaultStoredRequest.tap { - imp[0].ext.prebid.bidder.generic.exampleProperty = PBSUtils.randomNumber - } - - and: "Save storedRequest into DB" - def storedRequest = StoredRequest.getStoredRequest(bidRequest, storedRequestModel) - storedRequestDao.save(storedRequest) - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Bidder should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999] - assert response.ext?.warnings[PREBID]*.message == - ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + - "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + - "\$.exampleProperty: integer found, string expected", - "WARNING: request.imp[0].ext must contain at least one valid bidder"] - - and: "PBS should not call bidder" - assert bidder.getRequestCount(bidRequest.id) == 0 - - and: "seatbid should be empty" - assert response.seatbid.isEmpty() - } - - def "PBS should reject bidder when bidder params from stored request doesn't satisfy json-schema for amp request"() { - given: "AmpRequest with bad bidder datatype" - def ampRequest = AmpRequest.defaultAmpRequest - def ampStoredRequest = BidRequest.defaultBidRequest.tap { - site.publisher.id = ampRequest.account - imp[0].ext.prebid.bidder.generic.exampleProperty = PBSUtils.randomNumber - } - - and: "Save storedRequest into DB" - def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest) - storedRequestDao.save(storedRequest) - - when: "PBS processes amp request" - def response = defaultPbsService.sendAmpRequest(ampRequest) - - then: "Bidder should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999] - assert response.ext?.warnings[PREBID]*.message == - ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + - "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + - "\$.exampleProperty: integer found, string expected", - "WARNING: request.imp[0].ext must contain at least one valid bidder"] - - and: "PBS should not call bidder" - assert bidder.getRequestCount(ampStoredRequest.id) == 0 - - and: "targeting should be empty" - assert response.targeting.isEmpty() - } - - def "PBS should emit error when filter-imp-media-type = true and #configMediaType is empty in bidder config"() { - given: "Pbs config" - def pbsConfig = ["auction.filter-imp-media-type.enabled" : "true", - ("adapters.generic.meta-info.${configMediaType}".toString()): ""] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain empty seatbid" - assert response.seatbid.isEmpty() - - and: "Response should contain error" - assert response.ext?.warnings[GENERIC]*.code == [2] - assert response.ext?.warnings[GENERIC]*.message == ["Bidder does not support any media types."] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - - where: - configMediaType | bidRequest - "app-media-types" | BidRequest.getDefaultBidRequest(APP) - "site-media-types" | BidRequest.getDefaultBidRequest(SITE) - } - - def "PBS should not validate request when filter-imp-media-type = false and #configMediaType is empty in bidder config"() { - given: "Pbs config" - def pbsConfig = ["auction.filter-imp-media-type.enabled" : "false", - ("adapters.generic.meta-info.${configMediaType}".toString()): ""] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain seatbid" - assert response.seatbid - - and: "Response should not contain error" - assert !response.ext?.errors - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - - where: - configMediaType | bidRequest - "app-media-types" | BidRequest.getDefaultBidRequest(APP) - "site-media-types" | BidRequest.getDefaultBidRequest(SITE) - } - - def "PBS should emit error when filter-imp-media-type = true and request contains media type that is not configured in bidder config"() { - given: "Pbs config" - def pbsConfig = ["auction.filter-imp-media-type.enabled" : "true", - "adapters.generic.meta-info.site-media-types": "native"] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic BidRequest with banner, native" - def bidRequest = BidRequest.defaultBidRequest.tap { - site = Site.defaultSite - imp[0].banner = Banner.defaultBanner - imp[0].nativeObj = Native.defaultNative - } - - and: "Default basic bid with adm" - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest) - - and: "Set bidder response" - bidder.setResponse(bidRequest.id, bidResponse) - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "PBS should remove not configured media type from bidder request" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert !bidderRequest.imp[0]?.banner - assert bidderRequest.imp[0]?.nativeObj - - and: "Response should not contain warnings" - assert !response.ext?.warnings - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should not validate request when filter-imp-media-type = false and request contains only media type that is not configured in bidder config"() { - given: "Pbs config" - def pbsConfig = ["auction.filter-imp-media-type.enabled" : "false", - "adapters.generic.meta-info.site-media-types": "native"] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic BidRequest with banner, native" - def bidRequest = BidRequest.defaultBidRequest.tap { - site = Site.defaultSite - imp[0].banner = Banner.defaultBanner - imp[0].nativeObj = Native.defaultNative - } - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "PBS should not remove not configured media type from bidder request" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp[0]?.banner - assert bidderRequest.imp[0]?.nativeObj - - and: "Response should not contain error" - assert !response.ext?.errors - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should emit error for request with multiple impressions when filter-imp-media-type = true, one of imp doesn't contain supported media type"() { - given: "Pbs config" - def pbsConfig = ["auction.filter-imp-media-type.enabled" : "true", - "adapters.generic.meta-info.site-media-types": "native,video"] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic BidRequest with banner, native" - def nativeImp = Imp.getDefaultImpression(NATIVE) - def bidRequest = BidRequest.defaultBidRequest.tap { - site = Site.defaultSite - imp = [Imp.defaultImpression, nativeImp] - } - - and: "Default basic bid with adm" - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { - seatbid.first().bid = [Bid.getDefaultBid(nativeImp)] - } - - and: "Set bidder response" - bidder.setResponse(bidRequest.id, bidResponse) - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "PBS should remove banner imp from bidder request" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp.size() == 1 - assert !bidderRequest.imp[0].banner - assert bidderRequest.imp[0].nativeObj - - and: "Response should contain error" - assert response.ext?.warnings[GENERIC]*.code == [2] - assert response.ext?.warnings[GENERIC]*.message == - ["Imp ${bidRequest.imp[0].id} does not have a supported media type and has been removed from the " + - "request for this bidder." as String] - - and: "seatbid should not be empty" - assert !response.seatbid.isEmpty() - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS auction should reject the bidder with media-type that is not supported by DOOH configuration with proper warning"() { - given: "PBS service with configuration for dooh media-types" - def pbsConfig = ["auction.filter-imp-media-type.enabled" : "true", - "adapters.generic.meta-info.dooh-media-types": mediaType] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - when: "Requesting PBS auction" - def bidResponse = pbsService.sendAuctionRequest(bidRequest) - - then: "Bid response should contain proper warning" - assert bidResponse.ext?.warnings[GENERIC]?.message.contains("Bid request contains 0 impressions after filtering.") - - and: "Bid response shouldn't contain any seatbid" - assert !bidResponse.seatbid - - and: "Should't send any bidder request" - assert !bidder.getBidderRequests(bidRequest.id) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - - where: - mediaType | bidRequest - VIDEO.value | BidRequest.getDefaultBidRequest(DOOH) - NATIVE.value | BidRequest.getDefaultBidRequest(DOOH) - AUDIO.value | BidRequest.getDefaultBidRequest(DOOH) - BANNER.value | BidRequest.getDefaultVideoRequest(DOOH) - "${BANNER}, ${VIDEO}" as String | BidRequest.getDefaultBidRequest(DOOH).tap { imp[0] = Imp.getDefaultImpression(NATIVE) } - } - - def "PBS auction should reject only imps with media-type that is not supported by DOOH configuration with proper warning"() { - given: "PBS service with configuration for dooh media-types" - def pbsConfig = ["auction.filter-imp-media-type.enabled" : "true", - "adapters.generic.meta-info.dooh-media-types": mediaType.value] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid response with adm and nurl" - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { - seatbid[0].bid[0].adm = new Adm(assets: [titleAsset]) - seatbid[0].bid[0].nurl = PBSUtils.randomString - } - bidder.setResponse(bidRequest.id, bidResponse) - - when: "Requesting PBS auction" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Bid response should contain proper warning" - assert response.ext?.warnings[GENERIC]?.message == - ["Imp ${bidRequest.imp[1].id} does not have a supported media type and has been removed from the request for this bidder."] - - and: "Bid response should contain seatbid" - assert response.seatbid - - and: "Should send bidder request with only proper imp" - assert bidder.getBidderRequest(bidRequest.id).imp.id == [bidRequest.imp.first().id] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - - where: - mediaType | bidRequest - BANNER | BidRequest.getDefaultBidRequest(DOOH).tap { imp << Imp.getDefaultImpression(VIDEO) } - VIDEO | BidRequest.getDefaultVideoRequest(DOOH).tap { imp << Imp.getDefaultImpression(NATIVE) } - AUDIO | BidRequest.getDefaultAudioRequest(DOOH).tap { imp << Imp.getDefaultImpression(NATIVE) } - } - - def "PBS should return empty seatBit when filter-imp-media-type = true, request.imp doesn't contain supported media type"() { - given: "Pbs config" - def pbsConfig = ["auction.filter-imp-media-type.enabled" : "true", - "adapters.generic.meta-info.site-media-types": "native,video"] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic BidRequest with banner" - def bidRequest = BidRequest.defaultBidRequest.tap { - site = Site.defaultSite - imp.first().banner = Banner.defaultBanner - } - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "PBS should not call bidder" - assert bidder.getRequestCount(bidRequest.id) == 0 - - and: "Response should contain errors" - assert response.ext?.warnings[GENERIC]*.code == [2, 2] - assert response.ext?.warnings[GENERIC]*.message == - ["Imp ${bidRequest.imp[0].id} does not have a supported media type and has been removed from " + - "the request for this bidder.", - "Bid request contains 0 impressions after filtering."] - - and: "seatbid should be empty" - assert response.seatbid.isEmpty() - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should send server specific info to bidder when such is set in PBS config"() { - given: "PBS with server info configuration" - def serverDataCenter = PBSUtils.randomString - def serverExternalUrl = "https://${PBSUtils.randomString}.com/" - def serverHostVendorId = PBSUtils.randomNumber - def pbsConfig = ["datacenter-region" : serverDataCenter, - "external-url" : serverExternalUrl as String, - "gdpr.host-vendor-id": serverHostVendorId as String] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Bid request" - def bidRequest = BidRequest.defaultBidRequest - - when: "PBS auction is requested" - pbsService.sendAuctionRequest(bidRequest) - - then: "PBS has sent server info to bidder during auction" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - - assert bidderRequest?.ext?.prebid?.server?.externalUrl == serverExternalUrl - assert bidderRequest.ext.prebid.server.datacenter == serverDataCenter - assert bidderRequest.ext.prebid.server.gvlId == serverHostVendorId - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should request to bidder with header Content-Encoding = gzip when adapters.BIDDER.endpoint-compression = gzip"() { - given: "PBS with adapter configuration" - def compressionType = GZIP.value - def pbsConfig = ["adapters.generic.enabled" : "true", - "adapters.generic.endpoint-compression": compressionType] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid request" - def bidRequest = BidRequest.defaultBidRequest - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Bidder request should contain header Content-Encoding = gzip" - assert response.ext?.debug?.httpcalls?.get(BidderName.GENERIC.value)?.requestHeaders?.first() - ?.get(CONTENT_ENCODING_HEADER)?.first() == compressionType - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should send request to bidder without header Content-Encoding when adapters.BIDDER.endpoint-compression = none"() { - given: "PBS with adapter configuration" - def pbsConfig = ["adapters.generic.enabled" : "true", - "adapters.generic.endpoint-compression": NONE.value] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid request" - def bidRequest = BidRequest.defaultBidRequest - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Bidder request should not contain header Content-Encoding" - assert !response.ext?.debug?.httpcalls?.get(BidderName.GENERIC.value)?.requestHeaders?.first() - ?.get(CONTENT_ENCODING_HEADER) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should not treat reserved imp[].ext.tid object as a bidder"() { - given: "Default basic BidRequest with imp[].ext.tid object" - def bidRequest = BidRequest.defaultBidRequest - def tid = PBSUtils.getRandomString() - bidRequest.imp.first().ext.tid = tid - - when: "PBS processes auction request" - defaultPbsService.sendAuctionRequest(bidRequest) - - then: "imp[].ext.tid object should be passed to a bidder" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp?.first()?.ext?.tid == tid - } - - def "PBS auction should populate imp[0].secure depend which value in imp stored request"() { - given: "Default bid request" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomString) - } - - and: "Save storedImp into DB" - def storedImp = StoredImp.getStoredImp(bidRequest).tap { - impData = Imp.defaultImpression.tap { - it.secure = secureStoredRequest - } - } - storedImpDao.save(storedImp) - - when: "Requesting PBS auction" - defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Bidder request should contain imp[0].secure same value as in request" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp[0].secure == secureBidderRequest - - where: - secureStoredRequest | secureBidderRequest - null | SECURE - SECURE | SECURE - NON_SECURE | NON_SECURE - } - - def "PBS auction should populate imp[0].secure depend which value in imp request"() { - given: "Default bid request" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].secure = secureRequest - } - - when: "Requesting PBS auction" - defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain imp[0].secure same value as in request" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp[0].secure == secureBidderRequest - - where: - secureRequest | secureBidderRequest - null | SECURE - SECURE | SECURE - NON_SECURE | NON_SECURE - } - - def "PBS shouldn't emit warning and proceed auction when imp.ext.anyUnsupportedBidder and imp.ext.prebid.bidder.generic in the request"() { - given: "Default bid request" - def unsupportedBidder = new AnyUnsupportedBidder(anyUnsupportedField: PBSUtils.randomString) - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.anyUnsupportedBidder = unsupportedBidder - imp[0].ext.prebid.bidder.generic = new Generic() - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Bidder request should contain imp.ext.anyUnsupportedBidder" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp[0].ext.anyUnsupportedBidder == unsupportedBidder - - and: "Response shouldn't contain warning" - assert !response?.ext?.warnings - } - - def "PBS should emit warning and proceed auction when imp.ext.anyUnsupportedBidder and imp.ext.generic in the request"() { - given: "Default bid request" - def unsupportedBidder = new AnyUnsupportedBidder(anyUnsupportedField: PBSUtils.randomString) - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.generic = new Generic() - imp[0].ext.anyUnsupportedBidder = unsupportedBidder - imp[0].ext.prebid.bidder = null - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Bidder request should contain imp.ext.anyUnsupportedBidder" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.imp[0].ext.anyUnsupportedBidder == unsupportedBidder - - and: "PBS should emit an warning" - assert response?.ext?.warnings[PREBID]*.code == [999] - assert response?.ext?.warnings[PREBID]*.message == - ["WARNING: request.imp[0].ext.prebid.bidder.anyUnsupportedBidder was dropped with a reason: " + - "request.imp[0].ext.prebid.bidder contains unknown bidder: anyUnsupportedBidder"] - } - - def "PBS should emit warning and proceed auction when ext.prebid fields include adunitcode"() { - given: "Default bid request with populated ext.prebid.bidderParams" - def genericBidderParams = PBSUtils.randomString - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.bidderParams = [adUnitCode : PBSUtils.randomString, - (GENERIC.value): genericBidderParams] - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "PBS should emit an warning" - assert response?.ext?.warnings[PREBID]*.code == [999] - assert response?.ext?.warnings[PREBID]*.message == - ["WARNING: request.imp[0].ext.prebid.bidder.adUnitCode was dropped with a reason: " + - "request.imp[0].ext.prebid.bidder contains unknown bidder: adUnitCode"] - } - - def "PBS shouldn't emit warning and proceed auction when all imp.ext fields known for PBS"() { - given: "Default bid request with populated imp.ext" - def impExt = ImpExt.getDefaultImpExt().tap { - prebid.bidder.generic = null - prebid.adUnitCode = PBSUtils.randomString - generic = new Generic() - all = PBSUtils.randomNumber - context = new ImpExtContext(data: new ImpExtContextData()) - data = new ImpExtContextData(pbAdSlot: PBSUtils.randomString) - general = PBSUtils.randomString - gpid = PBSUtils.randomString - skadn = PBSUtils.randomString - tid = PBSUtils.randomString - } - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext = impExt - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "Response shouldn't contain warning" - assert !response.ext?.warnings - - and: "Bidder request should contain same field as requested" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - verifyAll(bidderRequest.imp[0].ext) { - it.bidder == impExt.generic - it.all == impExt.all - it.context == impExt.context - it.data == impExt.data - it.general == impExt.general - it.gpid == impExt.gpid - it.skadn == impExt.skadn - it.tid == impExt.tid - it.prebid.adUnitCode == impExt.prebid.adUnitCode - } - } - - def "PBS shouldn't emit warning and proceed auction when all imp.ext.prebid fields known for PBS"() { - given: "PBS with old ortb version" - def pbsConfig = ['adapters.generic.ortb-version': '2.5'] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid request with populated imp.ext.prebid" - def impExt = ImpExt.getDefaultImpExt().tap { - prebid.adUnitCode = PBSUtils.randomString - prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomString) - prebid.isRewardedInventory = PBSUtils.getRandomNumber(0, 1) - prebid.options = new PrebidOptions(echoVideoAttrs: PBSUtils.randomBoolean) - } - def bidRequest = BidRequest.defaultVideoRequest.tap { - imp[0].rwdd = null - imp[0].ext = impExt - } - - and: "Save storedImp into DB" - def storedImp = StoredImp.getStoredImp(bidRequest) - storedImpDao.save(storedImp) - - and: "Default bid response" - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest) - bidder.setResponse(bidRequest.id, bidResponse) - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "Response shouldn't contain warning" - assert !response.ext?.warnings - - and: "Bidder request should contain same field as requested" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - verifyAll(bidderRequest.imp[0].ext.prebid) { - it.adUnitCode == impExt.prebid.adUnitCode - it.storedRequest == impExt.prebid.storedRequest - it.isRewardedInventory == impExt.prebid.isRewardedInventory - it.options.echoVideoAttrs == impExt.prebid.options.echoVideoAttrs - } - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should proceed auction without warning when all ext.prebid.bidderParams fields are known"() { - given: "Default bid request with populated ext.prebid.bidderParams" - def genericBidderParams = PBSUtils.randomString - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.bidderParams = [all : PBSUtils.randomString, - context : PBSUtils.randomString, - data : PBSUtils.randomString, - general : PBSUtils.randomString, - gpid : PBSUtils.randomString, - skadn : PBSUtils.randomString, - tid : PBSUtils.randomString, - (GENERIC.value): genericBidderParams - ] - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "Response shouldn't contain warning" - assert !response.ext?.warnings - - and: "Bidder request should bidderParams only for bidder" - def bidderRequest = bidder.getBidderRequest(bidRequest.id) - assert bidderRequest.ext.prebid.bidderParams == [(GENERIC.value): genericBidderParams] - } - - def "PBS should send request to bidder when adapters.bidder.meta-info.currency-accepted not specified"() { - given: "PBS with adapter configuration" - def pbsConfig = ['adapters.generic.meta-info.currency-accepted': ''] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid request with generic bidder" - def bidRequest = BidRequest.defaultBidRequest.tap { - cur = [USD] - ext.prebid.returnAllBidStatus = true - } - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain http calls" - assert response.ext?.debug?.httpcalls[BidderName.GENERIC.value] - - and: "Response should contain seatBid" - assert response.seatbid.bid.flatten().size() == 1 - - and: "Bidder request should be valid" - assert bidder.getBidderRequest(bidRequest.id) - - and: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "Response shouldn't contain warning" - assert !response.ext?.warnings - - and: "PBS response shouldn't contain seatNonBid" - assert !response.ext.seatnonbid - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted not specified"() { - given: "PBS with adapter configuration" - def pbsConfig = [ - "adapters.generic.aliases.alias.enabled" : "true", - "adapters.generic.aliases.alias.meta-info.vendor-id" : "0", - "adapters.generic.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "adapters.generic.aliases.alias.meta-info.currency-accepted": ""] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid request with alias bidder" - def bidRequest = BidRequest.defaultBidRequest.tap { - cur = [USD] - ext.prebid.returnAllBidStatus = true - imp[0].ext.prebid.bidder.alias = new Generic() - imp[0].ext.prebid.bidder.generic = null - } - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain http calls" - assert response.ext?.debug?.httpcalls[BidderName.ALIAS.value] - - and: "Response should contain seatBid" - assert response.seatbid.bid.flatten().size() == 1 - - and: "Bidder request should be valid" - assert bidder.getBidderRequest(bidRequest.id) - - and: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "Response shouldn't contain warning" - assert !response.ext?.warnings - - and: "PBS response shouldn't contain seatNonBid" - assert !response.ext.seatnonbid - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should send request to bidder when adapters.bidder.meta-info.currency-accepted intersect with requested currency"() { - given: "PBS with adapter configuration" - def pbsConfig = ["adapters.generic.meta-info.currency-accepted": "${USD},${EUR}".toString()] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic generic BidRequest" - def bidRequest = BidRequest.defaultBidRequest.tap { - cur = [USD] - ext.prebid.returnAllBidStatus = true - } - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain http calls" - assert response.ext?.debug?.httpcalls[BidderName.GENERIC.value] - - and: "Response should contain seatBid" - assert response.seatbid.bid.flatten().size() == 1 - - and: "Bidder request should be valid" - assert bidder.getBidderRequest(bidRequest.id) - - and: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "Response shouldn't contain warning" - assert !response.ext?.warnings - - and: "PBS response shouldn't contain seatNonBid and contain errors" - assert !response.ext.seatnonbid - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS shouldn't send request to bidder and emit warning when adapters.bidder.meta-info.currency-accepted not intersect with requested currency"() { - given: "PBS with adapter configuration" - def pbsConfig = ["adapters.generic.meta-info.currency-accepted": "${JPY},${CHF}".toString()] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic generic BidRequest" - def bidRequest = BidRequest.defaultBidRequest.tap { - cur = [USD] - ext.prebid.returnAllBidStatus = true - } - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response shouldn't contain http calls" - assert !response.ext?.debug?.httpcalls - - and: "Response shouldn't contain seatBid" - assert !response.seatbid - - and: "Pbs shouldn't make bidder request" - assert !bidder.getBidderRequests(bidRequest.id) - - and: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "Response should seatNon bid with code 205" - assert response.ext.seatnonbid.size() == 1 - - and: "PBS should emit an warnings" - assert response.ext?.warnings[GENERIC]*.code == [999] - assert response.ext?.warnings[GENERIC]*.message == - ["No match between the configured currencies and bidRequest.cur"] - - def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == BidderName.GENERIC - assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id - assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted intersect with requested currency"() { - given: "PBS with adapter configuration" - def pbsConfig = [ - "adapters.generic.aliases.alias.enabled" : "true", - "adapters.generic.aliases.alias.meta-info.vendor-id" : "0", - "adapters.generic.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "adapters.generic.aliases.alias.meta-info.currency-accepted": "${USD},${EUR}".toString()] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic BidRequest with alias bidder" - def bidRequest = BidRequest.defaultBidRequest.tap { - cur = [USD] - ext.prebid.returnAllBidStatus = true - imp[0].ext.prebid.bidder.alias = new Generic() - imp[0].ext.prebid.bidder.generic = null - } - - and: "Default bid response" - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest) - bidder.setResponse(bidRequest.id, bidResponse) - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain http calls" - assert response.ext?.debug?.httpcalls[ALIAS.value] - - and: "Response should contain seatBid" - assert response.seatbid.bid.flatten().size() == 1 - - and: "Bidder request should be valid" - assert bidder.getBidderRequest(bidRequest.id) - - and: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "Response shouldn't contain warning" - assert !response.ext?.warnings - - and: "PBS response shouldn't contain seatNonBid and contain errors" - assert !response.ext.seatnonbid - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS shouldn't send request to bidder and emit warning when adapters.bidder.aliases.bidder.meta-info.currency-accepted not intersect with requested currency"() { - given: "PBS with adapter configuration" - def pbsConfig = [ - "adapters.generic.aliases.alias.enabled" : "true", - "adapters.generic.aliases.alias.meta-info.vendor-id" : "0", - "adapters.generic.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "adapters.generic.aliases.alias.meta-info.currency-accepted": "${JPY},${CHF}".toString()] - def pbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default basic BidRequest with alias bidder" - def bidRequest = BidRequest.defaultBidRequest.tap { - cur = [USD] - ext.prebid.returnAllBidStatus = true - imp[0].ext.prebid.bidder.alias = new Generic() - imp[0].ext.prebid.bidder.generic = null - } - - and: "Default bid response" - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest) - bidder.setResponse(bidRequest.id, bidResponse) - - when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) - - then: "Response shouldn't contain http calls" - assert !response.ext?.debug?.httpcalls - - and: "Response shouldn't contain seatBid" - assert !response.seatbid - - and: "Pbs shouldn't make bidder request" - assert !bidder.getBidderRequests(bidRequest.id) - - and: "Response shouldn't contain error" - assert !response.ext?.errors - - and: "PBS should emit an warnings" - assert response.ext?.warnings[ALIAS]*.code == [999] - assert response.ext?.warnings[ALIAS]*.message == - ["No match between the configured currencies and bidRequest.cur"] - - and: "Response should seatNon bid with code 205" - assert response.ext.seatnonbid.size() == 1 - - def seatNonBid = response.ext.seatnonbid[0] - assert seatNonBid.seat == BidderName.ALIAS - assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id - assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should reject alias bidders when bidder params from request doesn't satisfy own json-schema"() { - given: "Default bid request" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.bidder.tap { - it.generic.exampleProperty = PBSUtils.randomNumber - //Adrino hard coded bidder alias in generic.yaml - it.adrino = new Adrino(hash: PBSUtils.randomNumber) - } - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Bidder should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999, 999] - assert response.ext?.warnings[PREBID]*.message == - ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + - "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + - "\$.exampleProperty: integer found, string expected", - "WARNING: request.imp[0].ext.prebid.bidder.adrino was dropped with a reason: " + - "request.imp[0].ext.prebid.bidder.adrino failed validation.\n" + - "\$.hash: integer found, string expected", - "WARNING: request.imp[0].ext must contain at least one valid bidder"] - - and: "PBS should not call bidder" - assert bidder.getRequestCount(bidRequest.id) == 0 - - and: "targeting should be empty" - assert response.seatbid.isEmpty() - } - - def "PBS should reject alias bidders when bidder params from request doesn't satisfy aliased json-schema"() { - given: "Default basic generic BidRequest" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.bidder.tap { - it.generic.exampleProperty = PBSUtils.randomNumber - //Adrino hard coded bidder alias in generic.yaml - it.adrino = new Adrino(hash: PBSUtils.randomNumber) - } - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Bidder should be dropped" - assert response.ext?.warnings[PREBID]*.code == [999, 999, 999] - assert response.ext?.warnings[PREBID]*.message == - ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + - "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + - "\$.exampleProperty: integer found, string expected", - "WARNING: request.imp[0].ext.prebid.bidder.adrino was dropped with a reason: " + - "request.imp[0].ext.prebid.bidder.adrino failed validation.\n" + - "\$.hash: integer found, string expected", - "WARNING: request.imp[0].ext must contain at least one valid bidder"] - - and: "PBS should not call bidder" - assert bidder.getRequestCount(bidRequest.id) == 0 - - and: "targeting should be empty" - assert response.seatbid.isEmpty() - } - - def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode"() { - given: "Default basic bid request" - def bidRequest = BidRequest.defaultBidRequest - - and: "Default bid response" - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { - seatbid[0].seat = OPENX - } - bidder.setResponse(bidRequest.id, bidResponse) - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] - - and: "Bidder request should be valid" - assert bidder.getBidderRequest(bidRequest.id) - } - - def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode when requested soft alias"() { - given: "Default bid request with alias" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.bidder.tap { - generic = null - alias = new Generic() - } - ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] - ext.prebid.targeting = new Targeting() - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] - - and: "Response should contain seat bid" - assert response.seatbid.seat == [BidderName.ALIAS] - - and: "Response should contain bidder targeting" - def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${BidderName.ALIAS}"] - assert targeting["hb_size_${BidderName.ALIAS}"] - assert targeting["hb_bidder"] == BidderName.ALIAS.value - assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value - - and: "Response should contain repose millis with corresponding bidder" - assert response.ext.responsetimemillis.containsKey(ALIAS.value) - - and: "Bidder request should be valid and not contain aliases" - def bidderRequests = bidder.getBidderRequests(bidRequest.id).first - assert !bidderRequests.ext.prebid.aliases - } - - def "PBS should populate same code for adapter code when make call for generic hard code alias"() { - given: "PBS config with bidder" - def pbsConfig = ["adapters.generic.aliases.alias.enabled" : "true", - "adapters.generic.aliases.alias.meta-info.vendor-id": "0", - "adapters.generic.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString()] - def defaultPbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid request with alias" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.bidder.tap { - generic = null - alias = new Generic() - } - ext.prebid.targeting = new Targeting() - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] - - and: "Response should contain seat bid" - assert response.seatbid.seat == [BidderName.ALIAS] - - and: "Response should contain bidder targeting" - def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${BidderName.ALIAS}"] - assert targeting["hb_size_${BidderName.ALIAS}"] - assert targeting["hb_bidder"] == BidderName.ALIAS.value - assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value - - and: "Response should contain repose millis with corresponding bidder" - assert response.ext.responsetimemillis.containsKey(ALIAS.value) - - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should make call for alias when hard alias and demandSource specified"() { - given: "PBS config with bidder" - def pbsConfig = ["adapters.amx.enabled" : "true", - "adapters.amx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "adapters.amx.aliases.alias.enabled" : "true", - "adapters.amx.aliases.alias.meta-info.vendor-id": "0", - "adapters.amx.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString()] - def defaultPbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid Request with generic and openx bidder within separate imps" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.bidder.tap { - generic = null - alias = new Generic() - } - ext.prebid.targeting = new Targeting() - } - - and: "Bid response with bidder code" - def demandSource = PBSUtils.randomString - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, BidderName.ALIAS).tap { - it.seatbid[0].bid[0].ext = new BidExt(demandSource: demandSource) - } - bidder.setResponse(bidRequest.id, bidResponse) - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain demand source" - assert response.seatbid.bid.ext.prebid.meta.demandSource.flatten() == [demandSource] - - and: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] - - and: "Response should contain seat bid" - assert response.seatbid.seat == [BidderName.ALIAS] - - and: "Response should contain bidder targeting" - def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${BidderName.ALIAS}"] - assert targeting["hb_size_${BidderName.ALIAS}"] - assert targeting["hb_bidder"] == BidderName.ALIAS.value - assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value - - and: "Response should contain repose millis with corresponding bidder" - assert response.ext.responsetimemillis.containsKey(ALIAS.value) - - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode when requested soft alias with upper case"() { - given: "Default bid request with alias" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] - ext.prebid.targeting = new Targeting() - imp[0].ext.prebid.bidder.tap { - generic = null - aliasUpperCase = new Generic() - } - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] - - and: "Response should contain seat bid" - assert response.seatbid.seat == [ALIAS_UPPER_CASE] - - and: "Response should contain bidder targeting" - def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${ALIAS_UPPER_CASE}"] - assert targeting["hb_size_${ALIAS_UPPER_CASE}"] - assert targeting["hb_bidder"] == ALIAS_UPPER_CASE.value - assert targeting["hb_bidder_${ALIAS_UPPER_CASE}"] == ALIAS_UPPER_CASE.value - - and: "Response should contain repose millis with corresponding bidder" - assert response.ext.responsetimemillis.containsKey(ALIAS_UPPER_CASE.value) - - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) - } - - def "PBS should populate targeting with bidder in camel case when bidder with camel case was requested"() { - given: "Default bid request" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.bidder.generic = null - imp[0].ext.prebid.bidder.genericCamelCase = new Generic() - it.ext.prebid.targeting = new Targeting() - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain bidder targeting" - def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${GENERIC_CAMEL_CASE}"] - assert targeting["hb_size_${GENERIC_CAMEL_CASE}"] - assert targeting["hb_bidder"] == GENERIC_CAMEL_CASE.value - assert targeting["hb_bidder_${GENERIC_CAMEL_CASE}"] == GENERIC_CAMEL_CASE.value - - and: "Bid response should contain seat" - assert response.seatbid.seat == [GENERIC_CAMEL_CASE] - - and: "Response should contain repose millis with corresponding bidder" - assert response.ext.responsetimemillis.containsKey(GENERIC_CAMEL_CASE.value) - - and: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] - } - - def "PBS should make call for alias in upper case when soft alias specified with same name in upper case strategy"() { - given: "Default bid request with soft alias and targeting" - def bidRequest = BidRequest.defaultBidRequest.tap { - ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] - imp[0].ext.prebid.bidder.aliasUpperCase = new Generic() - imp[0].ext.prebid.bidder.generic = null - it.ext.prebid.targeting = new Targeting() - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] - - and: "Response should contain seat bid" - assert response.seatbid.seat == [ALIAS_UPPER_CASE] - - and: "Response should contain bidder targeting" - def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${ALIAS_UPPER_CASE}"] - assert targeting["hb_size_${ALIAS_UPPER_CASE}"] - assert targeting["hb_bidder"] == ALIAS_UPPER_CASE.value - assert targeting["hb_bidder_${ALIAS_UPPER_CASE}"] == ALIAS_UPPER_CASE.value - - and: "Response should contain repose millis with corresponding bidder" - assert response.ext.responsetimemillis.containsKey(ALIAS_UPPER_CASE.value) - - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) - } - - def "PBS should populate adapter code with requested bidder when conflict with soft and hard alias"() { - given: "PBS config with bidder" - def pbsConfig = ["adapters.amx.enabled" : "true", - "adapters.amx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "adapters.amx.aliases.alias.enabled" : "true", - "adapters.amx.aliases.alias.meta-info.vendor-id": "0", - "adapters.amx.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString()] - def defaultPbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Bid request with amx bidder and targeting" - def bidRequest = BidRequest.getDefaultBidRequest().tap { - imp[0].ext.prebid.bidder.alias = new Generic() - imp[0].ext.prebid.bidder.amx = null - imp[0].ext.prebid.bidder.generic = null - it.ext.prebid.aliases = [(ALIAS.value): BidderName.GENERIC] - it.ext.prebid.targeting = new Targeting() - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] - - and: "Response should contain seat bid" - assert response.seatbid.seat == [BidderName.ALIAS] - - and: "Response should contain bidder targeting" - def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${BidderName.ALIAS}"] - assert targeting["hb_size_${BidderName.ALIAS}"] - assert targeting["hb_bidder"] == BidderName.ALIAS.value - assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value - - and: "Response should contain repose millis with corresponding bidder" - assert response.ext.responsetimemillis.containsKey(ALIAS.value) - - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should populate adapter code with requested bidder when conflict with soft and generic hard alias"() { - given: "PBS config with bidders" - def pbsConfig = ["adapters.amx.enabled" : "true", - "adapters.amx.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "adapters.generic.aliases.alias.enabled" : "true", - "adapters.generic.aliases.alias.meta-info.vendor-id": "0", - "adapters.generic.aliases.alias.endpoint" : "$networkServiceContainer.rootUri/auction".toString()] - def defaultPbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Bid request with amx bidder and targeting" - def bidRequest = BidRequest.getDefaultBidRequest().tap { - imp[0].ext.prebid.bidder.alias = new Generic() - imp[0].ext.prebid.bidder.amx = null - imp[0].ext.prebid.bidder.generic = null - it.ext.prebid.aliases = [(ALIAS.value): AMX] - it.ext.prebid.targeting = new Targeting() - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.ALIAS] - - and: "Response should contain seat bid" - assert response.seatbid.seat == [BidderName.ALIAS] - - and: "Response should contain bidder targeting" - def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${BidderName.ALIAS}"] - assert targeting["hb_size_${BidderName.ALIAS}"] - assert targeting["hb_bidder"] == BidderName.ALIAS.value - assert targeting["hb_bidder_${BidderName.ALIAS}"] == BidderName.ALIAS.value - - and: "Response should contain repose millis with corresponding bidder" - assert response.ext.responsetimemillis.containsKey(ALIAS.value) - - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should properly populate bidder code when soft alias ignore standalone adapter"() { - given: "PBS config with amx bidder" - def pbsConfig = ["adapters.amx.enabled" : "true", - "adapters.amx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] - def defaultPbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default bid request with soft alias and targeting" - def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.prebid.bidder.amx = new Amx() - imp[0].ext.prebid.bidder.generic = null - ext.prebid.targeting = new Targeting() - ext.prebid.aliases = [(AMX.value): BidderName.GENERIC] - } - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Response should contain adapter code" - assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [AMX] - - and: "Response should contain seat" - assert response.seatbid.seat == [AMX] - - and: "Response should contain bidder targeting" - def targeting = response.seatbid[0].bid[0].ext.prebid.targeting - assert targeting["hb_pb_${AMX}"] - assert targeting["hb_size_${AMX}"] - assert targeting["hb_bidder"] == AMX.value - assert targeting["hb_bidder_${AMX}"] == AMX.value - - and: "Response should contain repose millis with corresponding bidder" - assert response.ext.responsetimemillis.containsKey(AMX.value) - - and: "Bidder request should be valid" - assert bidder.getBidderRequests(bidRequest.id) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } - - def "PBS should merge stored imp with appnexus bidder requested when reserve field specified"() { - given: "Pbs default config with appnexus" - def pbsConfig = ["adapters.${APPNEXUS.value}.enabled" : "true", - "adapters.${APPNEXUS.value}.endpoint": "$networkServiceContainer.rootUri/auction".toString()] - def defaultPbsService = pbsServiceFactory.getService(pbsConfig) - - and: "Default stored request with specified stored imps and request" - def storedRequestId = PBSUtils.randomString - def bidRequest = BidRequest.getDefaultBidRequest().tap { - imp[0].ext.prebid.bidder.generic = null - imp[0].ext.prebid.bidder.appNexus = AppNexus.getDefault().tap { - reserve = PBSUtils.getRandomDecimal() as Double - } - imp[0].ext.prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomString) - ext.prebid.storedRequest = new PrebidStoredRequest(id: storedRequestId) - } - - and: "Save storedImp into DB" - def storedImp = StoredImp.getStoredImp(bidRequest).tap { - impData = Imp.defaultImpression - } - storedImpDao.save(storedImp) - - and: "Save stored request with source.tid and cur" - def storedBidRequest = new BidRequest(cur: [USD], source: new Source(tid: PBSUtils.randomString)) - def storedRequest = StoredRequest.getStoredRequest(storedRequestId, storedBidRequest) - storedRequestDao.save(storedRequest) - - and: "Default basic bid with bid.ext" - def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, APPNEXUS).tap { - seatbid[0].bid[0].ext = new BidExt() - } - bidder.setResponse(bidRequest.id, bidResponse) - - when: "PBS processes auction request" - def response = defaultPbsService.sendAuctionRequest(bidRequest) - - then: "Bid response should contain appnexus and generic bidder" - assert response.seatbid.size() == 2 - assert response.seatbid.seat.sort() == [APPNEXUS, BidderName.GENERIC].sort() - - and: "Bidder requests should perform two bidder call" - def bidderRequests = bidder.getBidderRequests(bidRequest.id) - assert bidderRequests.size() == 2 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - } -} diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index 372d5045817..314cfbc09ad 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -152,9 +152,6 @@ class CacheSpec extends BaseSpec { and: "PBS call shouldn't include api-key" assert !prebidCache.getRequestHeaders(bidRequest.imp[0].id)[PBS_API_HEADER] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should cache bids with api-key header when targeting is specified and api-key-secured enabled"() { @@ -177,9 +174,6 @@ class CacheSpec extends BaseSpec { and: "PBS call should include api-key" assert prebidCache.getRequestHeaders(bidRequest.imp[0].id)[PBS_API_HEADER] == [apiKey] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should cache banner bids with cache key that include account and datacenter short name when append-trace-info-to-cache-id enabled"() { @@ -215,9 +209,6 @@ class CacheSpec extends BaseSpec { def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should cache video bids with cache key that include account and datacenter short name when append-trace-info-to-cache-id enabled"() { @@ -262,9 +253,6 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics prebid_cache_creative.{xml,json}.creative.ttl for general" assert metrics[JSON_CREATIVE_TTL_METRIC] == videoHostTtl assert metrics[XML_CREATIVE_TTL_METRIC] == videoHostTtl - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should cache bids with cache key that include account when append-trace-info-to-cache-id enabled and datacenter is null"() { @@ -299,9 +287,6 @@ class CacheSpec extends BaseSpec { def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should cache bids without cache key when account ID is too large"() { @@ -335,9 +320,6 @@ class CacheSpec extends BaseSpec { def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should cache bids without cache key when append-trace-info-to-cache-id disabled"() { @@ -369,9 +351,6 @@ class CacheSpec extends BaseSpec { def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should not cache bids when targeting isn't specified"() { @@ -507,9 +486,6 @@ class CacheSpec extends BaseSpec { and: "PBS shouldn't call PBC" assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 0 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(INVALID_PREBID_CACHE_CONFIG) } def "PBS should cache bids and emit error when targeting is specified and config cache is valid and internal is invalid"() { @@ -544,9 +520,6 @@ class CacheSpec extends BaseSpec { then: "Response should contain error" assert bidResponse.ext?.errors[CACHE]*.code == [999] assert bidResponse.ext?.errors[CACHE]*.message[0] == ("Failed to resolve '${CACHE_HOST.tokenize(":")[0]}' [A(1)]") - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(INVALID_PREBID_CACHE_CONFIG) } def "PBS should cache bids when targeting is specified and config cache is invalid and internal cache config valid"() { @@ -583,9 +556,6 @@ class CacheSpec extends BaseSpec { and: "Debug should contain http call" assert bidResponse.ext.debug.httpcalls['cache'][0].uri == "${HTTPS_SCHEME}://${CACHE_HOST + CACHE_PATH}" - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(INVALID_PREBID_CACHE_CONFIG + VALID_INTERNAL_CACHE_CONFIG) } def "PBS should cache bids when targeting is specified and config cache and internal cache config valid"() { @@ -619,9 +589,6 @@ class CacheSpec extends BaseSpec { and: "Debug should contain http call" assert bidResponse.ext.debug.httpcalls['cache'][0].uri == "${HTTP_SCHEME}://${networkServiceContainer.hostAndPort + INTERNAL_CACHE_PATH}" - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(VALID_INTERNAL_CACHE_CONFIG) } def "PBS should cache bids and add targeting values when account cache config #accountAuctionConfig"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy index bfab691b3f3..65928a35970 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy @@ -12,6 +12,7 @@ import org.prebid.server.functional.model.request.vtrack.xml.Vast import org.prebid.server.functional.model.response.vtrack.TransferValue import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.util.PBSUtils import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST @@ -37,12 +38,12 @@ class CacheVtrackSpec extends BaseSpec { private static final String CACHE_HOST = "${PBSUtils.randomString}:${PBSUtils.getRandomNumber(0, 65535)}".toString() private static final String HTTP_SCHEME = 'http' - private static final Map INVALID_PREBID_CACHE_CONFIG = ["cache.path" : CACHE_PATH, + private static final PbsContainerConfig INVALID_PREBID_CACHE_CONFIG = new PbsContainerConfig(["cache.path" : CACHE_PATH, "cache.scheme": HTTP_SCHEME, - "cache.host" : CACHE_HOST] - private static final Map VALID_INTERNAL_CACHE = ["cache.internal.scheme": HTTP_SCHEME, + "cache.host" : CACHE_HOST]) + private static final PbsContainerConfig VALID_INTERNAL_CACHE = new PbsContainerConfig(["cache.internal.scheme": HTTP_SCHEME, "cache.internal.host" : "$networkServiceContainer.hostAndPort".toString(), - "cache.internal.path" : CACHE_ENDPOINT] + "cache.internal.path" : CACHE_ENDPOINT]) private static PrebidServerService pbsServiceWithInternalCache def setupSpec() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/CookieSyncPriSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CookieSyncPriSpec.groovy new file mode 100644 index 00000000000..cdd5f902658 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/CookieSyncPriSpec.groovy @@ -0,0 +1,293 @@ +package org.prebid.server.functional.tests + +import org.prebid.server.functional.model.config.AccountConfig +import org.prebid.server.functional.model.config.AccountCookieSyncConfig +import org.prebid.server.functional.model.config.AccountCoopSyncConfig +import org.prebid.server.functional.model.db.Account +import org.prebid.server.functional.model.request.cookiesync.CookieSyncRequest +import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.util.PBSUtils +import spock.lang.IgnoreRest + +import java.time.Instant + +import static org.prebid.server.functional.model.AccountStatus.ACTIVE +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC +import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer +import static org.prebid.server.functional.util.privacy.TcfConsent.GENERIC_VENDOR_ID + +class CookieSyncPriSpec extends BaseSpec { + + private static final String USER_SYNC_URL = "$networkServiceContainer.rootUri/generic-usersync" + private static final boolean CORS_SUPPORT = false + private static final Map GENERIC_CONFIG = [ + "adapters.${GENERIC.value}.usersync.redirect.url" : USER_SYNC_URL, + "adapters.${GENERIC.value}.usersync.redirect.support-cors": CORS_SUPPORT as String, + "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String] + + private static final Map COOP_SYNC_ENABLED_CONFIG = ["cookie-sync.coop-sync.default": "true", + "cookie-sync.pri" : GENERIC.value] + GENERIC_CONFIG + private static final Map COOP_SYNC_DISABLED_CONFIG = ["cookie-sync.coop-sync.default": "false", + "cookie-sync.pri" : GENERIC.value] + GENERIC_CONFIG + + private static PrebidServerService pbsWithCoopSyncDefault = pbsServiceFactory.getService(COOP_SYNC_ENABLED_CONFIG) + private static PrebidServerService pbsWithoutCoopSyncDefault = pbsServiceFactory.getService(COOP_SYNC_DISABLED_CONFIG) + + def "PBS cookie sync with cookie-sync.pri and enabled coop-sync in config should sync bidder which present in cookie-sync.pri config"() { + given: "Default cookie sync request without coop-sync and bidders" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + bidders = null + coopSync = null + } + + when: "PBS processes cookie sync request" + def response = pbsWithCoopSyncDefault.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response should contain generic bidder from cookie-sync.pri config" + def genericBidder = response.getBidderUserSync(GENERIC) + assert genericBidder?.userSync?.url + assert genericBidder?.userSync?.type + } + + def "PBS cookie sync with cookie-sync.pri and disabled coop-sync in config shouldn't sync bidder which present in cookie-sync.pri config"() { + given: "Default cookie sync request without coop-sync and bidders" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + bidders = null + coopSync = null + } + + when: "PBS processes cookie sync request" + def response = pbsWithoutCoopSyncDefault.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response shouldn't contain generic bidder from cookie-sync.pri config" + assert !response.getBidderUserSync(GENERIC) + } + + def "PBS should prioritise disable account cookie sync config oover #configType host config and shouldn't sync bidder"() { + given: "Default cookie sync request without coop-sync and bidders" + def accountId = PBSUtils.randomNumber + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + bidders = null + coopSync = null + account = accountId + } + + and: "Save account with cookie config" + def cookieSyncConfig = new AccountCookieSyncConfig(coopSync: new AccountCoopSyncConfig(enabled: false)) + def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) + def account = new Account(uuid: accountId, config: accountConfig) + accountDao.save(account) + + when: "PBS processes cookie sync request" + def response = pbsService.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response shouldn't contain generic bidder which present in cookie-sync.pri config" + assert !response.getBidderUserSync(GENERIC) + + where: + configType | pbsService + "enabled coop-sync" | pbsWithCoopSyncDefault + "disabled coop-sync"| pbsWithoutCoopSyncDefault + } + + def "PBS should prioritise enable account cookie sync config over #configType host config and should sync bidder"() { + given: "Default cookie sync request without coop-sync and bidders" + def accountId = PBSUtils.randomNumber + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + bidders = null + coopSync = null + account = accountId + } + + and: "Save account with cookie config" + def cookieSyncConfig = new AccountCookieSyncConfig(coopSync: new AccountCoopSyncConfig(enabled: true)) + def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) + def account = new Account(uuid: accountId, config: accountConfig) + accountDao.save(account) + + when: "PBS processes cookie sync request" + def response = pbsService.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response should contain generic bidder from cookie-sync.pri config" + def genericBidder = response.getBidderUserSync(GENERIC) + assert genericBidder?.userSync?.url + assert genericBidder?.userSync?.type + + where: + configType | pbsService + "enabled coop-sync" | pbsWithCoopSyncDefault + "disabled coop-sync"| pbsWithoutCoopSyncDefault + } + + def "PBS cookie sync with enabled coop-sync should log error when prioritized bidder name is invalid"() { + given: "Start time" + def startTime = Instant.now() + + and: "PBS config with invalid prioritized bidder" + def prebidServerService = pbsServiceFactory.getService([ + "cookie-sync.pri": PBSUtils.randomString + ]) + + and: "Cookie sync request with coop-sync enabled" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + coopSync = true + } + + when: "PBS processes cookie sync request" + prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + + then: "PBS log should contain invalid bidder message" + def logs = prebidServerService.getLogsByTime(startTime) + assert getLogsByText(logs, "is invalid bidder name, ignoring").size() == 1 + } + + def "PBS cookie sync with enabled coop-sync should log error when prioritized bidder is disabled"() { + given: "Start time" + def startTime = Instant.now() + + and: "PBS config with disabled prioritized bidder" + def prebidServerService = pbsServiceFactory.getService([ + "adapters.generic.enabled": "false", + "cookie-sync.pri" : GENERIC.value + ]) + + and: "Cookie sync request with coop-sync enabled" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + coopSync = true + } + + when: "PBS processes cookie sync request" + prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + + then: "PBS log should contain disabled bidder message" + def logs = prebidServerService.getLogsByTime(startTime) + assert getLogsByText(logs, "disabled in current pbs instance, ignoring").size() == 1 + } + + def "PBS cookie sync with enabled coop-sync should log error when prioritized bidder has no user sync configuration"() { + given: "Start time" + def startTime = Instant.now() + + and: "PBS config with prioritized bidder without user sync configuration" + def prebidServerService = pbsServiceFactory.getService([ + "adapters.generic.usersync.cookie-family-name": null, + "cookie-sync.pri" : GENERIC.value + ]) + + and: "Cookie sync request with coop-sync enabled" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + coopSync = true + } + + when: "PBS processes cookie sync request" + prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + + then: "PBS log should contain missing user sync configuration message" + def logs = prebidServerService.getLogsByTime(startTime) + assert getLogsByText(logs, "has no user-sync configuration, ignoring").size() == 1 + } + + def "PBS cookie sync with cookie-sync.pri and enabled coop sync should sync bidder which present in cookie-sync.pri"() { + given: "Default cookie sync request with coop-sync" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + bidders = null + coopSync = true + } + + when: "PBS processes cookie sync request" + def response = pbsWithoutCoopSyncDefault.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response should contain generic bidder" + def genericBidder = response.getBidderUserSync(GENERIC) + assert genericBidder?.userSync?.url + assert genericBidder?.userSync?.type + } + + def "PBS cookie sync with cookie-sync.pri and disabled coop-sync in request shouldn't sync bidder which present in cookie-sync.pri config"() { + given: "Default cookie sync request without coop-sync and bidders" + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + bidders = null + coopSync = false + } + + when: "PBS processes cookie sync request" + def response = pbsWithoutCoopSyncDefault.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response shouldn't contain generic bidder" + assert !response.getBidderUserSync(GENERIC) + } + + def "PBS cookie sync with cookie-sync.pri and enabled coop sync in account should sync bidder which present in cookie-sync.pri config"() { + given: "Default cookie sync request without coop-sync and bidders" + def accountId = PBSUtils.randomNumber + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.bidders = null + it.coopSync = null + it.account = accountId + } + + and: "Save account with cookie config" + def cookieSyncConfig = new AccountCookieSyncConfig(coopSync: new AccountCoopSyncConfig(enabled: true)) + def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) + def account = new Account(uuid: accountId, config: accountConfig) + accountDao.save(account) + + when: "PBS processes cookie sync request" + def response = pbsWithoutCoopSyncDefault.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response should contain generic bidder from cookie-sync.pri config" + def genericBidder = response.getBidderUserSync(GENERIC) + assert genericBidder?.userSync?.url + assert genericBidder?.userSync?.type + } + + def "PBS cookie sync with coop-sync.default config and pri in cookie sync account should sync bidder which present in pri account config"() { + given: "Default cookie sync request without coop-sync and bidders" + def accountId = PBSUtils.randomNumber + PrebidServerService pbsWithGenericCors = pbsServiceFactory.getService(GENERIC_CONFIG) + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + bidders = null + coopSync = null + account = accountId + } + + and: "Save account with cookie config" + def cookieSyncConfig = new AccountCookieSyncConfig(pri: [GENERIC.value]) + def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) + def account = new Account(uuid: accountId, config: accountConfig) + accountDao.save(account) + + when: "PBS processes cookie sync request" + def response = pbsWithGenericCors.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response should contain generic bidder from pri account config" + def genericBidder = response.getBidderUserSync(GENERIC) + assert genericBidder?.userSync?.url + assert genericBidder?.userSync?.type + } + + def "PBS cookie sync with pri and enabled coop sync in cookie sync account should sync bidder which present in pri account config"() { + given: "Default cookie sync request without coop-sync and bidders" + PrebidServerService pbsWithGenericCors = pbsServiceFactory.getService(GENERIC_CONFIG) + def accountId = PBSUtils.randomNumber + def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { + it.bidders = null + it.coopSync = null + it.account = accountId + } + + and: "Save account with cookie config" + def cookieSyncConfig = new AccountCookieSyncConfig(pri: [GENERIC.value], coopSync: new AccountCoopSyncConfig(enabled: true)) + def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) + def account = new Account(uuid: accountId, config: accountConfig) + accountDao.save(account) + + when: "PBS processes cookie sync request" + def response = pbsWithGenericCors.sendCookieSyncRequest(cookieSyncRequest) + + then: "Response should contain generic bidder from pri account config" + def genericBidder = response.getBidderUserSync(GENERIC) + assert genericBidder?.userSync?.url + assert genericBidder?.userSync?.type + } +} diff --git a/src/test/groovy/org/prebid/server/functional/tests/CookieSyncSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CookieSyncSpec.groovy index 43453891d1a..7f2faee8079 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CookieSyncSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CookieSyncSpec.groovy @@ -18,12 +18,12 @@ import org.prebid.server.functional.model.response.cookiesync.CookieSyncResponse import org.prebid.server.functional.model.response.cookiesync.UserSyncInfo import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.util.HttpUtil import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.CcpaConsent import org.prebid.server.functional.util.privacy.TcfConsent -import java.time.Instant import java.util.concurrent.TimeUnit import static org.prebid.server.functional.model.AccountStatus.ACTIVE @@ -35,8 +35,8 @@ import static org.prebid.server.functional.model.bidder.BidderName.ALIAS import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS import static org.prebid.server.functional.model.bidder.BidderName.BOGUS import static org.prebid.server.functional.model.bidder.BidderName.GENERIC -import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.bidder.BidderName.MAGNITE +import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.request.cookiesync.FilterType.EXCLUDE import static org.prebid.server.functional.model.request.cookiesync.FilterType.INCLUDE import static org.prebid.server.functional.model.response.cookiesync.CookieSyncResponse.Status.NO_COOKIE @@ -49,95 +49,99 @@ import static org.prebid.server.functional.testcontainers.Dependencies.networkSe import static org.prebid.server.functional.util.HttpUtil.SET_COOKIE_HEADER import static org.prebid.server.functional.util.privacy.CcpaConsent.Signal.ENFORCED import static org.prebid.server.functional.util.privacy.TcfConsent.GENERIC_VENDOR_ID -import static org.prebid.server.functional.util.privacy.TcfConsent.PurposeId.BASIC_ADS import static org.prebid.server.functional.util.privacy.TcfConsent.MAGNITE_VENDOR_ID +import static org.prebid.server.functional.util.privacy.TcfConsent.PurposeId.BASIC_ADS class CookieSyncSpec extends BaseSpec { private static final UserSyncInfo.Type USER_SYNC_TYPE = REDIRECT + private static final boolean CORS_SUPPORT = false + private static final Integer COOKIE_SYNC_DEFAULT_LIMIT = 2 + private static final Integer COOKIE_SYNC_MAX_LIMIT = 3 + private static final String RANDOM_COOKIE_NAME = PBSUtils.randomString + private static final String USER_SYNC_URL = "$networkServiceContainer.rootUri/generic-usersync" private static final String ALL_BIDDERS = "*" - private static final Integer DEFAULT_PBS_BIDDERS_SIZE = 8 + private static final List DEFAULT_PBS_BIDDERS = [GENERIC, ACEEX, MAGNITE, OPENX, APPNEXUS, AAX, ADKERNEL] + private static final Map COOKIE_SYNC_CONFIG = [ + "cookie-sync.max-limit" : COOKIE_SYNC_MAX_LIMIT.toString(), + "cookie-sync.default-limit": COOKIE_SYNC_DEFAULT_LIMIT.toString()] private static final Map GENERIC_CONFIG = [ - "adapters.${GENERIC.value}.usersync.redirect.url" : USER_SYNC_URL, - "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String] + "adapters.${GENERIC.value}.usersync.redirect.url": USER_SYNC_URL + '&redir={redirect_url}', + "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String] private static final Map ACEEX_CONFIG = [ - "adapters.${ACEEX.value}.enabled" : "true", - "adapters.${ACEEX.value}.usersync.cookie-family-name" : ACEEX.value, - "adapters.${ACEEX.value}.usersync.redirect.url" : "https://test.redirect.endpoint.com={redirect_url}"] + "adapters.${ACEEX.value}.enabled" : "true", + "adapters.${ACEEX.value}.usersync.cookie-family-name": ACEEX.value, + "adapters.${ACEEX.value}.usersync.redirect.url" : "https://test.redirect.endpoint.com={redirect_url}"] private static final Map MAGNITE_CONFIG = [ - "adapters.${MAGNITE.value}.enabled" : "true", - "adapters.${MAGNITE.value}.meta-info.vendor-id" : MAGNITE_VENDOR_ID as String, - "adapters.${MAGNITE.value}.usersync.cookie-family-name" : MAGNITE.value, - "adapters.${MAGNITE.value}.usersync.redirect.url" : "https://test.redirect.endpoint.com", - "adapters.${MAGNITE.value}.usersync.iframe.url" : "https://test.iframe.endpoint.com&redir={redirect_url}"] + "adapters.${MAGNITE.value}.enabled" : "true", + "adapters.${MAGNITE.value}.meta-info.vendor-id" : MAGNITE_VENDOR_ID as String, + "adapters.${MAGNITE.value}.usersync.cookie-family-name": MAGNITE.value, + "adapters.${MAGNITE.value}.usersync.redirect.url" : "https://test.redirect.endpoint.com", + "adapters.${MAGNITE.value}.usersync.iframe.url" : "https://test.iframe.endpoint.com&redir={redirect_url}"] private static final Map OPENX_CONFIG = [ - "adapters.${OPENX.value}.enabled" : "true", - "adapters.${OPENX.value}.usersync.cookie-family-name" : OPENX.value, - "adapters.${OPENX.value}.usersync.redirect.url" : USER_SYNC_URL, - "adapters.${OPENX.value}.usersync.iframe.url" : USER_SYNC_URL] + "adapters.${OPENX.value}.enabled" : "true", + "adapters.${OPENX.value}.usersync.cookie-family-name": OPENX.value, + "adapters.${OPENX.value}.usersync.redirect.url" : USER_SYNC_URL, + "adapters.${OPENX.value}.usersync.iframe.url" : USER_SYNC_URL] private static final Map APPNEXUS_CONFIG = [ - "adapters.${APPNEXUS.value}.enabled" : "true", - "adapters.${APPNEXUS.value}.aliases.mediafuse.enabled" : "false", - "adapters.${APPNEXUS.value}.usersync.cookie-family-name" : APPNEXUS.value, - "adapters.${APPNEXUS.value}.usersync.redirect.url" : "https://test.appnexus.redirect.com/getuid?{redirect_url}"] + "adapters.${APPNEXUS.value}.enabled" : "true", + "adapters.${APPNEXUS.value}.aliases.mediafuse.enabled" : "false", + "adapters.${APPNEXUS.value}.usersync.cookie-family-name": APPNEXUS.value, + "adapters.${APPNEXUS.value}.usersync.redirect.url" : "https://test.appnexus.redirect.com/getuid?{redirect_url}"] + private static final Map ALIAS_NO_FAMILY_CONFIG = [ + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.enabled" : "true", + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.usersync.cookie-family-name": null] + private static final Map BOGUS_CONFIG = ["adapters.${BOGUS.value}.enabled": "true"] private static final Map AAX_CONFIG = ["adapters.${AAX.value}.enabled": "true"] - private static final Map ACUITYADS_CONFIG = ["adapters.${ACUITYADS.value}.enabled": "true"] + private static final Map ACUITYADS_CONFIG = ["adapters.${ACUITYADS.value}.enabled": "false"] private static final Map ADKERNEL_CONFIG = [ "adapters.${ADKERNEL.value}.enabled" : "true", "adapters.${ADKERNEL.value}.aliases.rxnetwork.enabled": "false", "adapters.${ADKERNEL.value}.aliases.152media.enabled" : "false" - ] - private static final Map PBS_CONFIG = APPNEXUS_CONFIG + MAGNITE_CONFIG + OPENX_CONFIG + - GENERIC_CONFIG + ACEEX_CONFIG + AAX_CONFIG + ACUITYADS_CONFIG + ADKERNEL_CONFIG + - ["cookie-sync.pri": "grid, ix, adkernel"] + private static final PbsContainerConfig PBS_CONFIG = new PbsContainerConfig(APPNEXUS_CONFIG + MAGNITE_CONFIG + OPENX_CONFIG + + GENERIC_CONFIG + ACEEX_CONFIG + AAX_CONFIG + ACUITYADS_CONFIG + ADKERNEL_CONFIG + BOGUS_CONFIG + + ["cookie-sync.pri": "grid, ix, adkernel"]) - private final PrebidServerService prebidServerService = pbsServiceFactory.getService(PBS_CONFIG) + private static final PrebidServerService pbsWithoutLimitService = pbsServiceFactory.getService(PBS_CONFIG) + private static final PrebidServerService prebidServerService = pbsServiceFactory.getService(PBS_CONFIG + COOKIE_SYNC_CONFIG) + private static final PrebidServerService pbsWithAliasService = pbsServiceFactory.getService(PBS_CONFIG + ALIAS_NO_FAMILY_CONFIG) - def "PBS cookie sync request shouldn't replace synced as family bidder and fill up response with enabled bidders to the limit in request"() { - given: "PBS config with alias bidder without cookie family name" - def bidderAlias = ALIAS - def prebidServerService = pbsServiceFactory.getService(GENERIC_CONFIG + APPNEXUS_CONFIG - + ["adapters.${GENERIC.value}.aliases.${bidderAlias.value}.enabled" : "true", - "adapters.${GENERIC.value}.aliases.${bidderAlias.value}.meta-info.vendor-id" : "0", - "adapters.${GENERIC.value}.aliases.${bidderAlias.value}.usersync.cookie-family-name": null]) + def cleanupSpec() { + pbsServiceFactory.removeContainer(PBS_CONFIG) + pbsServiceFactory.removeContainer(PBS_CONFIG + COOKIE_SYNC_CONFIG) + pbsServiceFactory.removeContainer(PBS_CONFIG + ALIAS_NO_FAMILY_CONFIG) + } - and: "Default cookie sync request" + def "PBS cookie sync request shouldn't replace synced as family bidder and fill up response with enabled bidders to the limit in request"() { + given: "Default cookie sync request" def requestLimit = 2 def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = [bidderAlias] + bidders = [ALIAS] limit = requestLimit coopSync = true debug = false } when: "PBS processes cookie sync request without cookies" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithAliasService.sendCookieSyncRequest(cookieSyncRequest) - then: "Response should contain synced bidder" - assert response.bidderStatus.size() == requestLimit - - and: "Response shouldn't contain family bidder" + then: "Response shouldn't contain source bidder" assert !response.getBidderUserSync(GENERIC) and: "Response should contain coop-synced bidder" - assert response.getBidderUserSync(bidderAlias) - assert response.getBidderUserSync(APPNEXUS) + assert response.bidderStatus.size() == requestLimit + assert response.getBidderUserSync(ALIAS) } +// @IgnoreRest def "PBS cookie sync should use requested bidder name in sync url instead of cookie family name"() { - given: "PBS config with alias bidder using source bidder cookie family name" + given: "Cookie sync request for alias bidder" def bidderAlias = ALIAS - def prebidServerService = pbsServiceFactory.getService(GENERIC_CONFIG + - ["adapters.${GENERIC.value}.usersync.redirect.url" : "$networkServiceContainer.rootUri/generic-usersync&redir={redirect_url}".toString(), - "adapters.${GENERIC.value}.aliases.${bidderAlias.value}.enabled" : "true", - "adapters.${GENERIC.value}.aliases.${bidderAlias.value}.meta-info.vendor-id" : "0", - "adapters.${GENERIC.value}.aliases.${bidderAlias.value}.usersync.cookie-family-name": GENERIC.value]) - - and: "Cookie sync request for alias bidder" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { bidders = [bidderAlias] limit = 1 @@ -146,7 +150,7 @@ class CookieSyncSpec extends BaseSpec { } when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithAliasService.sendCookieSyncRequest(cookieSyncRequest) then: "Response shouldn't contain source bidder" assert !response.getBidderUserSync(GENERIC) @@ -162,11 +166,7 @@ class CookieSyncSpec extends BaseSpec { } def "PBS cookie sync request should replace bidder without config and fill up response with enabled bidders to the limit in request"() { - given: "PBS bidder config" - def prebidServerService = pbsServiceFactory.getService(MAGNITE_CONFIG + GENERIC_CONFIG - + ["adapters.${BOGUS.value}.enabled": "true"]) - - and: "Default Cookie sync request" + given: "Default Cookie sync request" def requestLimit = 2 def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { bidders = [BOGUS] @@ -185,15 +185,11 @@ class CookieSyncSpec extends BaseSpec { assert !response.getBidderUserSync(BOGUS) and: "Response should contain coop-synced bidder" - assert response.getBidderUserSync(MAGNITE) - assert response.getBidderUserSync(GENERIC) + assert DEFAULT_PBS_BIDDERS.containsAll(response.bidderStatus.bidder) } def "PBS cookie sync request should replace unknown bidder and fill up response with enabled bidders to the limit in request"() { - given: "PBS bidder config" - def prebidServerService = pbsServiceFactory.getService(MAGNITE_CONFIG + APPNEXUS_CONFIG) - - and: "Cookie sync request" + given: "Cookie sync request" def requestLimit = 2 def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { bidders = [BOGUS] @@ -212,14 +208,13 @@ class CookieSyncSpec extends BaseSpec { assert !response.getBidderUserSync(BOGUS) and: "Response should contain coop-synced bidder" - assert response.getBidderUserSync(MAGNITE) - assert response.getBidderUserSync(APPNEXUS) + assert DEFAULT_PBS_BIDDERS.containsAll(response.bidderStatus.bidder) } def "PBS cookie sync request should replace disabled bidder and fill up response with enabled bidders to the limit in request"() { given: "PBS bidder config" def prebidServerService = pbsServiceFactory.getService(MAGNITE_CONFIG + APPNEXUS_CONFIG - + ["adapters.${GENERIC.value}.enabled": "false",]) + + ["adapters.${GENERIC.value}.enabled": "false"]) and: "Default Cookie sync request" def requestLimit = 2 @@ -240,15 +235,11 @@ class CookieSyncSpec extends BaseSpec { assert !response.getBidderUserSync(GENERIC) and: "Response should contain coop-synced bidder" - assert response.getBidderUserSync(MAGNITE) - assert response.getBidderUserSync(APPNEXUS) + assert DEFAULT_PBS_BIDDERS.containsAll(response.bidderStatus.bidder) } def "PBS cookie sync request should replace filtered bidder and fill up response with enabled bidders to the limit in request"() { - given: "PBS bidder config" - def prebidServerService = pbsServiceFactory.getService(MAGNITE_CONFIG + APPNEXUS_CONFIG) - - and: "Cookie sync request" + given: "Cookie sync request" def requestLimit = 2 def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { bidders = [GENERIC] @@ -268,16 +259,11 @@ class CookieSyncSpec extends BaseSpec { assert !response.getBidderUserSync(GENERIC) and: "Response should contain coop-synced bidder" - assert response.getBidderUserSync(MAGNITE) - assert response.getBidderUserSync(APPNEXUS) + assert DEFAULT_PBS_BIDDERS.containsAll(response.bidderStatus.bidder) } def "PBS cookie sync request shouldn't reflect error when coop-sync enabled and coop sync bidder disabled"() { - given: "PBS bidder config " - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG - + ["adapters.${GENERIC.value}.enabled": "false"]) - - and: "Default cookie sync request" + given: "Default cookie sync request" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { bidders = null coopSync = true @@ -287,7 +273,7 @@ class CookieSyncSpec extends BaseSpec { def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) then: "Response shouldn't return error" - assert !response.getBidderUserSync(GENERIC) + assert response.bidderStatus.error.every { it == null } } def "PBS cookie sync request shouldn't reflect error when coop-sync enabled and coop sync bidder without sync config"() { @@ -324,24 +310,17 @@ class CookieSyncSpec extends BaseSpec { } def "PBS cookie sync request shouldn't reflect error when coop-sync enabled and coop sync bidder synced"() { - given: "PBS config with alias bidder without cookie family name" - def bidderAlias = ALIAS - def prebidServerService = pbsServiceFactory.getService(GENERIC_CONFIG - + ["adapters.${GENERIC.value}.aliases.${bidderAlias.value}.enabled" : "true", - "adapters.${GENERIC.value}.aliases.${bidderAlias.value}.meta-info.vendor-id" : "0", - "adapters.${GENERIC.value}.aliases.${bidderAlias.value}.usersync.cookie-family-name": null]) - - and: "Cookie sync request with 2 bidders" + given: "Cookie sync request with 2 bidders" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = [bidderAlias] + bidders = [ALIAS] coopSync = true } when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithAliasService.sendCookieSyncRequest(cookieSyncRequest) then: "Response shouldn't contain bidder error" - def bidderStatus = response.getBidderUserSync(bidderAlias) + def bidderStatus = response.getBidderUserSync(ALIAS) assert !bidderStatus?.error and: "Response should indicate bidder has no cookie" @@ -349,7 +328,7 @@ class CookieSyncSpec extends BaseSpec { and: "Response should contain bidder user sync information" verifyAll(bidderStatus?.userSync) { - it.url == USER_SYNC_URL + bidderStatus?.userSync?.url?.startsWith(USER_SYNC_URL) it.type == REDIRECT } } @@ -382,34 +361,6 @@ class CookieSyncSpec extends BaseSpec { assert metric["cookie_sync.generic.tcf.blocked"] == 1 } - def "PBS cookie sync request should reflect error when coop-sync enabled and coop sync bidder with ccpa"() { - given: "PBS bidder config" - def bidderName = GENERIC - def prebidServerService = pbsServiceFactory.getService( - ["adapters.${bidderName.value}.ccpa-enforced": "true"] + GENERIC_CONFIG) - - and: "Cookie sync request with account and privacy" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = [] - account = PBSUtils.randomString - usPrivacy = new CcpaConsent(optOutSale: ENFORCED) - coopSync = true - } - - and: "Save account config into DB" - def ccpaConfig = new AccountCcpaConfig(enabled: true) - def accountConfig = new AccountConfig(privacy: new AccountPrivacyConfig(ccpa: ccpaConfig)) - def account = new Account(uuid: cookieSyncRequest.account, config: accountConfig) - accountDao.save(account) - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response should contain error" - def bidderStatus = response.getBidderUserSync(bidderName) - assert bidderStatus.error == "Rejected by CCPA" - } - def "PBS cookie sync request should reflect error when coop-sync enabled and coop sync bidder filtered"() { given: "Default cookie sync request" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { @@ -463,29 +414,20 @@ class CookieSyncSpec extends BaseSpec { } def "PBS cookie sync request should reflect error even when response is full by PBS config limit"() { - given: "PBS config with expanded limit" - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.default-limit": "1"] + PBS_CONFIG) - - and: "Default cookie sync request with coop-sync and without bidders" + given: "Default cookie sync request with coop-sync and without bidders" + def cookieSyncBidders = [GENERIC, MAGNITE, APPNEXUS] def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = [GENERIC, BOGUS] + bidders = cookieSyncBidders } when: "PBS processes cookie sync request" def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - then: "Response should contain 1 valid bidder and 1 bidder with error" - assert response.bidderStatus.size() == 2 - - and: "Response should contain generic" - assert response.getBidderUserSync(GENERIC) - - and: "Response should contain error for bogus bidder" - def bogusBidderStatus = response.getBidderUserSync(BOGUS) - assert bogusBidderStatus?.error == "Unsupported bidder" - assert bogusBidderStatus?.noCookie == null - assert bogusBidderStatus?.userSync == null + then: "Response should contain valid bidders and 1 bidder with error" + assert verifyAll(response.bidderStatus) { + it.bidder.sort() == cookieSyncBidders.sort() + it.error.sort() == [null, null, "Limit reached"].sort() + } } def "PBS cookie sync request should reflect error even when response is full by request limit"() { @@ -657,30 +599,21 @@ class CookieSyncSpec extends BaseSpec { } def "PBS cookie sync request with disabled bidder should emit an error"() { - given: "PBS config with disabled bidder" - def prebidServerService = pbsServiceFactory.getService( - ["adapters.${GENERIC.value}.enabled": "false"]) - - and: "Default cookie sync request" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest + given: "Default cookie sync request" + def cookieSyncRequest = CookieSyncRequest.getDefaultCookieSyncRequest([ACUITYADS]) when: "PBS processes cookie sync request" def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should contain error" - def bidderStatus = response.getBidderUserSync(GENERIC) + def bidderStatus = response.getBidderUserSync(ACUITYADS) assert bidderStatus?.error == "Disabled bidder" assert bidderStatus?.noCookie == null assert bidderStatus?.userSync == null } def "PBS cookie sync with enabled coop-sync should sync all enabled bidders"() { - given: "PBS config with expanded limit" - def countOfEnabledBidders = 3 - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.default-limit": countOfEnabledBidders.toString()] + PBS_CONFIG) - - and: "Default cookie sync request with coop-sync and without bidders" + given: "Default cookie sync request with coop-sync and without bidders" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { bidders = null coopSync = true @@ -689,35 +622,26 @@ class CookieSyncSpec extends BaseSpec { when: "PBS processes cookie sync request" def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - then: "Response should contain all 3 enabled bidders" - assert response.bidderStatus.size() == countOfEnabledBidders + then: "Response should contain all 2 enabled bidders" + assert response.bidderStatus.size() == COOKIE_SYNC_DEFAULT_LIMIT } - def "PBS cookie sync request should resolve alias and source bidder into a single sync when alias doesn't override cookie-family-name"() { - given: "PBS config with alias bidder without cookie family name" - def bidderAlias = ALIAS - def prebidServerService = pbsServiceFactory.getService(PBS_CONFIG - + ["adapters.${GENERIC.value}.aliases.${bidderAlias.value}.enabled" : "true", - "adapters.${GENERIC.value}.aliases.${bidderAlias.value}.meta-info.vendor-id" : "0", - "adapters.${GENERIC.value}.aliases.${bidderAlias.value}.usersync.cookie-family-name": null]) - - and: "Cookie sync request with 2 bidders" + def "PBS cookie sync request with alias bidder should sync as the source bidder when alias doesn't override cookie-family-name"() { + given: "Cookie sync request with 2 bidders" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = [GENERIC, bidderAlias] + bidders = [GENERIC, ALIAS] } when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithAliasService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should have status 'NO_COOKIE'" assert response.status == NO_COOKIE and: "Response should contain sync information for single resolved bidder" def validBidderUserSyncs = getValidBidderUserSyncs(response).values().toList() - verifyAll(validBidderUserSyncs) { - it.url == [USER_SYNC_URL] - it.type == [USER_SYNC_TYPE] - } + assert validBidderUserSyncs.url.every { it.startsWith(USER_SYNC_URL) } + assert validBidderUserSyncs.type == [USER_SYNC_TYPE] and: "Response should contain duplicate bidder error" def rejectedBidderStatus = getRejectedBidderUserSyncs(response).values().toList() @@ -751,10 +675,9 @@ class CookieSyncSpec extends BaseSpec { def "PBS cookie sync request with host cookie should return bidder sync with host cookie uid when there is no uids cookie"() { given: "PBS bidders config" - def cookieName = PBSUtils.randomString def prebidServerService = pbsServiceFactory.getService( ["host-cookie.family" : GENERIC.value, - "host-cookie.cookie-name": cookieName] + PBS_CONFIG) + "host-cookie.cookie-name": RANDOM_COOKIE_NAME] + PBS_CONFIG) and: "Default cookie sync request" def uidsCookie = UidsCookie.defaultUidsCookie @@ -764,7 +687,7 @@ class CookieSyncSpec extends BaseSpec { and: "Host cookie" def uid = UUID.randomUUID().toString() - def cookies = [(cookieName): uid] + def cookies = [(RANDOM_COOKIE_NAME): uid] when: "PBS processes cookie sync request with cookies" def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest, uidsCookie, cookies) @@ -776,10 +699,9 @@ class CookieSyncSpec extends BaseSpec { def "PBS cookie sync request with host cookie should return bidder sync with host cookie uid when uids are different"() { given: "PBS bidders config" - def cookieName = PBSUtils.randomString def prebidServerService = pbsServiceFactory.getService( ["host-cookie.family" : GENERIC.value, - "host-cookie.cookie-name": cookieName] + PBS_CONFIG) + "host-cookie.cookie-name": RANDOM_COOKIE_NAME] + PBS_CONFIG) and: "Default cookie sync request" def uidsCookie = UidsCookie.defaultUidsCookie.tap { @@ -791,7 +713,7 @@ class CookieSyncSpec extends BaseSpec { and: "Host cookie" def hostCookieUid = UUID.randomUUID().toString() - def cookies = [(cookieName): hostCookieUid] + def cookies = [(RANDOM_COOKIE_NAME): hostCookieUid] when: "PBS processes cookie sync request with cookies" def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest, uidsCookie, cookies) @@ -803,10 +725,9 @@ class CookieSyncSpec extends BaseSpec { def "PBS cookie sync request with host cookie should return an error when host cookie uid matches uids cookie uid for bidder"() { given: "PBS bidders config" - def cookieName = PBSUtils.randomString def prebidServerService = pbsServiceFactory.getService( ["host-cookie.family" : GENERIC.value, - "host-cookie.cookie-name": cookieName] + PBS_CONFIG) + "host-cookie.cookie-name": RANDOM_COOKIE_NAME] + PBS_CONFIG) and: "Default cookie sync request" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest @@ -818,7 +739,7 @@ class CookieSyncSpec extends BaseSpec { } and: "Host cookie" - def cookies = [(cookieName): uid] + def cookies = [(RANDOM_COOKIE_NAME): uid] when: "PBS processes cookie sync request" def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest, uidsCookie, cookies) @@ -830,32 +751,6 @@ class CookieSyncSpec extends BaseSpec { assert bidderStatus?.userSync == null } - def "PBS cookie sync request with host cookie shouldn't return bidder sync when host cookie doesn't match requested bidder"() { - given: "PBS bidders config" - def prebidServerService = pbsServiceFactory.getService( - ["host-cookie.family" : PBSUtils.randomString, - "host-cookie.cookie-name": PBSUtils.randomString] + PBS_CONFIG) - - and: "Default cookie sync request" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest - def uidsCookie = UidsCookie.defaultUidsCookie - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest, uidsCookie) - - then: "Response should contain already in sync bidder" - def bidderStatus = response.getBidderUserSync(GENERIC) - assert bidderStatus?.error == "Already in sync" - assert bidderStatus?.noCookie == null - assert bidderStatus?.userSync == null - - where: - hostCookieFamily || hostCookieName - PBSUtils.randomString || PBSUtils.randomString - null || PBSUtils.randomString - PBSUtils.randomString || null - } - def "PBS cookie sync request with host cookie shouldn't return bidder sync when host cookie doesn't have configured name"() { given: "PBS bidders config" def bidderName = GENERIC @@ -873,25 +768,24 @@ class CookieSyncSpec extends BaseSpec { def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest, uidsCookie) then: "Response should contain already in sync bidder" - def bidderStatus = response.getBidderUserSync(GENERIC) + def bidderStatus = response.getBidderUserSync(bidderName) assert bidderStatus?.error == "Already in sync" assert bidderStatus?.noCookie == null assert bidderStatus?.userSync == null } - def "PBS cookie sync without cookie-sync.default-limit config and with cookie sync account config limit should use limit from request"() { + def "PBS cookie sync with cookie-sync.default-limit config should use limit from cookie sync config"() { given: "Default cookie sync request with 3 bidders" - def requestLimit = 1 def accountId = PBSUtils.randomNumber def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - limit = requestLimit - bidders = [MAGNITE, APPNEXUS, GENERIC] - account = accountId - debug = false + it.bidders = [MAGNITE, APPNEXUS, GENERIC] + it.account = accountId + it.limit = requestLimit + it.debug = false } - and: "Save account with cookie sync config" - def cookieSyncConfig = new AccountCookieSyncConfig(defaultLimit: 2) + and: "Save account with cookie config" + def cookieSyncConfig = new AccountCookieSyncConfig(defaultLimit: accountLimit) def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) def account = new Account(uuid: accountId, config: accountConfig) accountDao.save(account) @@ -900,25 +794,27 @@ class CookieSyncSpec extends BaseSpec { def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should contain one synced bidder" - assert response.bidderStatus.size() == requestLimit - } + assert response.bidderStatus.size() == 1 - def "PBS cookie sync with cookie-sync.default-limit config should use limit from cookie sync account config"() { - given: "PBS bidders config" - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.default-limit": "2"] + PBS_CONFIG) + where: + requestLimit | accountLimit + 1 | null + null | 1 + } - and: "Default cookie sync request with 3 bidders" + def "PBS cookie sync request should take precedence request limit over account and global config"() { + given: "Default cookie sync request with 3 bidders" def accountId = PBSUtils.randomNumber + def requestLimit = 1 def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = [MAGNITE, APPNEXUS, GENERIC] - account = accountId - debug = false + it.bidders = [MAGNITE, APPNEXUS, GENERIC] + it.account = accountId + it.limit = requestLimit + it.debug = false } and: "Save account with cookie config" - def accountDefaultLimit = 1 - def cookieSyncConfig = new AccountCookieSyncConfig(defaultLimit: accountDefaultLimit) + def cookieSyncConfig = new AccountCookieSyncConfig(defaultLimit: requestLimit + 1) def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) def account = new Account(uuid: accountId, config: accountConfig) accountDao.save(account) @@ -927,59 +823,14 @@ class CookieSyncSpec extends BaseSpec { def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should contain one synced bidder" - assert response.bidderStatus.size() == accountDefaultLimit - } - - def "PBS cookie sync with cookie-sync.default-limit config should use limit from request"() { - given: "PBS config" - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.default-limit": "2"] + PBS_CONFIG) - - and: "Default cookie sync request with 3 bidders" - def requestLimit = 1 - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - limit = requestLimit - bidders = [MAGNITE, APPNEXUS, GENERIC] - debug = false - } - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response should contain only two synced bidder" assert response.bidderStatus.size() == requestLimit } - def "PBS cookie sync with cookie-sync.default-limit config should use limit from PBS config"() { - given: "PBS config" - def defaultLimit = 1 - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.default-limit": defaultLimit.toString()] + PBS_CONFIG) - - and: "Default cookie sync request with 2 bidders" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = [GENERIC, MAGNITE] - debug = false - } - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response should contain only one synced bidder" - assert response.bidderStatus.size() == defaultLimit - } - def "PBS cookie sync with cookie-sync.max-limit should use max-limit from PBS config"() { - given: "PBS bidders config" - def maxLimit = 2 - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.max-limit" : maxLimit.toString(), - "cookie-sync.default-limit": "1"] + PBS_CONFIG) - - and: "Default cookie sync request with 3 bidders" + given: "Default cookie sync request with 3 bidders" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { bidders = [GENERIC, APPNEXUS, MAGNITE] - limit = 5 + limit = COOKIE_SYNC_MAX_LIMIT + 1 debug = false } @@ -987,20 +838,15 @@ class CookieSyncSpec extends BaseSpec { def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should contain only one synced bidder" - assert response.bidderStatus.size() == maxLimit + assert response.bidderStatus.size() == COOKIE_SYNC_MAX_LIMIT } def "PBS cookie sync with cookie-sync.max-limit should use max-limit from cookie sync account config"() { - given: "PBS bidders config" - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.default-limit": "1", - "cookie-sync.max-limit" : "1"] + PBS_CONFIG) - - and: "Default cookie sync request with 3 bidders" + given: "Default cookie sync request with 3 bidders" def accountId = PBSUtils.randomNumber def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = [GENERIC, APPNEXUS, MAGNITE] - limit = 5 + bidders = DEFAULT_PBS_BIDDERS + limit = COOKIE_SYNC_MAX_LIMIT + 2 account = accountId debug = false } @@ -1015,83 +861,14 @@ class CookieSyncSpec extends BaseSpec { def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should contain only two synced bidder" - assert response.bidderStatus.size() == 2 + assert response.bidderStatus.size() == COOKIE_SYNC_MAX_LIMIT + 1 where: - accountMaxLimit | accountMaxLimitSnakeCase - 2 | null - null | 2 - } - - def "PBS cookie sync with cookie-sync.pri and enabled coop-sync in config should sync bidder which present in cookie-sync.pri config"() { - given: "PBS bidders config" - def bidderName = GENERIC - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.coop-sync.default": "true", - "cookie-sync.pri" : bidderName.value] + GENERIC_CONFIG) - - and: "Default cookie sync request without coop-sync and bidders" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = null - coopSync = null - } - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response should contain generic bidder from cookie-sync.pri config" - def genericBidder = response.getBidderUserSync(bidderName) - assert genericBidder?.userSync?.url - assert genericBidder?.userSync?.type + accountMaxLimit | accountMaxLimitSnakeCase + COOKIE_SYNC_MAX_LIMIT + 1 | null + null | COOKIE_SYNC_MAX_LIMIT + 1 } - def "PBS cookie sync with cookie-sync.pri and disabled coop-sync in config shouldn't sync bidder which present in cookie-sync.pir config"() { - given: "PBS bidders config" - def bidderName = GENERIC - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.coop-sync.default": "false", - "cookie-sync.pri" : bidderName.value] + GENERIC_CONFIG) - - and: "Default cookie sync request without coop-sync and bidders" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = null - coopSync = null - } - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response shouldn't contain generic bidder from cookie-sync.pri config" - assert !response.getBidderUserSync(bidderName) - } - - def "PBS cookie sync with cookie-sync.pri and in all places disabled coop sync in account shouldn't sync bidder which present in cookie-sync.pir config"() { - given: "PBS bidders config" - def bidderName = GENERIC - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.pri" : bidderName.value, - "cookie-sync.coop-sync.default": "false"] + GENERIC_CONFIG) - - and: "Default cookie sync request without coop-sync and bidders" - def accountId = PBSUtils.randomNumber - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = null - coopSync = null - account = accountId - } - - and: "Save account with cookie config" - def cookieSyncConfig = new AccountCookieSyncConfig(coopSync: new AccountCoopSyncConfig(enabled: false)) - def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) - def account = new Account(uuid: accountId, config: accountConfig) - accountDao.save(account) - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response shouldn't contain generic bidder which present in cookie-sync.pri config" - assert !response.getBidderUserSync(bidderName) - } def "PBS cookie sync should sync bidder by limit value"() { given: "PBS config with bidders usersync config" @@ -1122,231 +899,6 @@ class CookieSyncSpec extends BaseSpec { assert rejectedBidderUserSyncs.every { it.value == "Limit reached" } } - def "PBS cookie sync with enabled coop-sync in request and when bidder invalid should log error: bidder is provided for prioritized coop-syncing but #reason"() { - given: "Start time" - def startTime = Instant.now() - - and: "PBS config" - def prebidServerService = pbsServiceFactory.getService(config) - - and: "Cookie sync request with coop-sync" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - coopSync = true - } - - when: "PBS processes cookie sync request" - prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "PBS log should contain message" - def logs = prebidServerService.getLogsByTime(startTime) - assert getLogsByText(logs, reason).size() == 1 - - where: - reason | config - "is invalid bidder name, ignoring" | ["cookie-sync.pri": PBSUtils.randomString] - "disabled in current pbs instance, ignoring" | ["adapters.generic.enabled": "false", - "cookie-sync.pri" : GENERIC.value] - "has no user-sync configuration, ignoring" | ["adapters.generic.usersync.cookie-family-name": "null", - "cookie-sync.pri" : GENERIC.value] - } - - def "PBS cookie sync with enabled coop-sync in PBS config and when bidder invalid should log error: bidder is provided for prioritized coop-syncing but #reason"() { - given: "Start time" - def startTime = Instant.now() - - and: "PBS config" - def prebidServerService = pbsServiceFactory.getService(config + - ["cookie-sync.coop-sync.default": "true"]) - - and: "Cookie sync request with coop-sync" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - coopSync = null - } - - when: "PBS processes cookie sync request" - prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "PBS log should contain message" - def logs = prebidServerService.getLogsByTime(startTime) - assert getLogsByText(logs, reason).size() == 1 - - where: - reason | config - "is invalid bidder name, ignoring" | ["cookie-sync.pri": PBSUtils.randomString] - "disabled in current pbs instance, ignoring" | ["adapters.generic.enabled": "false", - "cookie-sync.pri" : GENERIC.value] - "has no user-sync configuration, ignoring" | ["adapters.generic.usersync.cookie-family-name": "null", - "cookie-sync.pri" : GENERIC.value] - } - - def "PBS cookie sync with enabled coop-sync in account cookie sync and when bidder invalid should log error: bidder is provided for prioritized coop-syncing but #reason"() { - given: "Start time" - def startTime = Instant.now() - - and: "PBS config" - def prebidServerService = pbsServiceFactory.getService(config + - ["cookie-sync.coop-sync.default": "false"]) - - and: "Cookie sync request with disabled coop-sync" - def accountId = PBSUtils.randomNumber - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - coopSync = null - account = accountId - } - - and: "Save account with cookie config" - def cookieSyncConfig = new AccountCookieSyncConfig(coopSync: new AccountCoopSyncConfig(enabled: false)) - def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) - def account = new Account(uuid: accountId, config: accountConfig) - accountDao.save(account) - - when: "PBS processes cookie sync request" - prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "PBS log should contain message" - def logs = prebidServerService.getLogsByTime(startTime) - assert getLogsByText(logs, reason).size() == 1 - - where: - reason | config - "is invalid bidder name, ignoring" | ["cookie-sync.pri": PBSUtils.randomString] - "disabled in current pbs instance, ignoring" | ["adapters.generic.enabled": "false", - "cookie-sync.pri" : GENERIC.value] - "has no user-sync configuration, ignoring" | ["adapters.generic.usersync.cookie-family-name": "null", - "cookie-sync.pri" : GENERIC.value] - } - - def "PBS cookie sync with cookie-sync.pri and enabled coop sync should sync bidder which present in cookie-sync.pri"() { - given: "PBS bidders config" - def bidderName = GENERIC - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.pri" : bidderName.value, - "cookie-sync.coop-sync.default": "false"] + GENERIC_CONFIG) - - and: "Default cookie sync request with coop-sync" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = null - coopSync = true - } - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response should contain generic bidder" - def genericBidder = response.getBidderUserSync(bidderName) - assert genericBidder?.userSync?.url - assert genericBidder?.userSync?.type - } - - def "PBS cookie sync with pri and enabled coop sync in cookie sync account should sync bidder which present in pir account config"() { - given: "PBS bidders config" - def bidderName = GENERIC - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.pri" : "null", - "cookie-sync.coop-sync.default": "false"] + GENERIC_CONFIG) - - and: "Default cookie sync request without coop-sync and bidders" - def accountId = PBSUtils.randomNumber - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = null - coopSync = null - account = accountId - } - - and: "Save account with cookie config" - def cookieSyncConfig = new AccountCookieSyncConfig(pri: [bidderName.value], coopSync: new AccountCoopSyncConfig(enabled: true)) - def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) - def account = new Account(uuid: accountId, config: accountConfig) - accountDao.save(account) - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response should contain generic bidder from pri account config" - def genericBidder = response.getBidderUserSync(bidderName) - assert genericBidder?.userSync?.url - assert genericBidder?.userSync?.type - } - - def "PBS cookie sync with coop-sync.default config and pri in cookie sync account should sync bidder which present in pir account config"() { - given: "PBS bidders config" - def bidderName = GENERIC - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.pri" : "null", - "cookie-sync.coop-sync.default": "true"] + GENERIC_CONFIG) - - and: "Default cookie sync request without coop-sync and bidders" - def accountId = PBSUtils.randomNumber - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = null - coopSync = null - account = accountId - } - - and: "Save account with cookie config" - def cookieSyncConfig = new AccountCookieSyncConfig(pri: [bidderName.value]) - def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) - def account = new Account(uuid: accountId, config: accountConfig) - accountDao.save(account) - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response should contain generic bidder from pri account config" - def genericBidder = response.getBidderUserSync(bidderName) - assert genericBidder?.userSync?.url - assert genericBidder?.userSync?.type - } - - def "PBS cookie sync with cookie-sync.pri and enabled coop sync in account should sync bidder which present in cookie-sync.pir config"() { - given: "PBS bidders config" - def bidderName = GENERIC - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.pri" : bidderName.value, - "cookie-sync.coop-sync.default": "false"] + GENERIC_CONFIG) - - and: "Default cookie sync request without coop-sync and bidders" - def accountId = PBSUtils.randomNumber - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = null - coopSync = null - account = accountId - } - - and: "Save account with cookie config" - def cookieSyncConfig = new AccountCookieSyncConfig(coopSync: new AccountCoopSyncConfig(enabled: true)) - def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) - def account = new Account(uuid: accountId, config: accountConfig) - accountDao.save(account) - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response should contain generic bidder from cookie-sync.pri config" - def genericBidder = response.getBidderUserSync(bidderName) - assert genericBidder?.userSync?.url - assert genericBidder?.userSync?.type - } - - def "PBS cookie sync with cookie-sync.pri and disabled coop-sync in request shouldn't sync bidder which present in cookie-sync.pri config"() { - given: "PBS bidders config" - def bidderName = GENERIC - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.pri" : bidderName.value, - "cookie-sync.coop-sync.default": "false"] + GENERIC_CONFIG) - - and: "Default cookie sync request without coop-sync and bidders" - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = null - coopSync = false - } - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response shouldn't contain generic bidder" - assert !response.getBidderUserSync(bidderName) - } def "PBS cookie sync with filter setting should reject bidder sync"() { given: "Cookie sync request with filter settings" @@ -1421,20 +973,15 @@ class CookieSyncSpec extends BaseSpec { } def "PBS cookie sync should emit error when requested bidder rejected by limit"() { - given: "PBS config with bidders usersync config" + given: "Default cookie sync request with 2 bidders" def limit = 1 - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.max-limit" : limit as String, - "cookie-sync.default-limit": limit as String] + PBS_CONFIG) - - and: "Default cookie sync request with 2 bidders" - def bidders = [GENERIC, MAGNITE] def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - it.bidders = bidders + it.bidders = DEFAULT_PBS_BIDDERS + it.limit = limit } when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should contain only one valid user sync" def validBidderUserSyncs = getValidBidderUserSyncs(response) @@ -1442,20 +989,16 @@ class CookieSyncSpec extends BaseSpec { and: "Discarded bidder user sync should contain an error" def rejectedBidderUserSyncs = getRejectedBidderUserSyncs(response) - assert rejectedBidderUserSyncs.size() == bidders.size() - limit + assert rejectedBidderUserSyncs.size() == DEFAULT_PBS_BIDDERS.size() - limit assert rejectedBidderUserSyncs.every { it.value == "Limit reached" } } def "PBS cookie sync shouldn't emit error limit reached when bidder coop-synced"() { - given: "PBS config with bidders usersync config" - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.max-limit" : "1", - "cookie-sync.default-limit": "1"] + PBS_CONFIG) - - and: "Default cookie sync request with 2 bidders" + given: "Default cookie sync request with single bidder" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - coopSync = true - bidders = [MAGNITE] + it.coopSync = true + it.bidders = [MAGNITE] + it.limit = 1 } when: "PBS processes cookie sync request" @@ -1470,7 +1013,7 @@ class CookieSyncSpec extends BaseSpec { def cookieSyncRequest = new CookieSyncRequest() when: "PBS processes cookie sync request without cookies" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should have status 'NO_COOKIE'" assert response.status == NO_COOKIE @@ -1486,7 +1029,7 @@ class CookieSyncSpec extends BaseSpec { assert HttpUtil.findUrlParameterValue(magniteBidderStatus.userSync?.url, "f") == BLANK.name and: "Response should contain coop-synced bidder" - assert response.bidderStatus.bidder.containsAll(ADKERNEL, ACUITYADS, ACEEX, APPNEXUS, AAX, MAGNITE, OPENX, GENERIC) + assert response.bidderStatus.bidder.containsAll(DEFAULT_PBS_BIDDERS) } def "PBS cookie sync request shouldn't return bidder due to filter setting request"() { @@ -1575,7 +1118,7 @@ class CookieSyncSpec extends BaseSpec { def cookieSyncRequest = new CookieSyncRequest(filterSettings: filterSettings, limit: 0) when: "PBS processes cookie sync request without cookies" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should have status 'NO_COOKIE'" assert response.status == NO_COOKIE @@ -1593,7 +1136,7 @@ class CookieSyncSpec extends BaseSpec { def cookieSyncRequest = new CookieSyncRequest(filterSettings: filterSettings, limit: 0) when: "PBS processes cookie sync request without cookies" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should have status 'NO_COOKIE'" assert response.status == NO_COOKIE @@ -1648,14 +1191,13 @@ class CookieSyncSpec extends BaseSpec { def cookieSyncRequest = new CookieSyncRequest(account: null) when: "PBS processes cookie sync request without cookies" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should have status 'NO_COOKIE'" assert response.status == NO_COOKIE and: "Response should contain configured bidders" - assert response?.getBidderStatus()?.bidder?.sort() == - [GENERIC, MAGNITE, APPNEXUS, OPENX, ACEEX, ACUITYADS, AAX, ADKERNEL].sort() + assert response?.getBidderStatus()?.bidder?.sort() == DEFAULT_PBS_BIDDERS.sort() } def "PBS cookie sync request should return url for all bidders when no uids cookie is present"() { @@ -1682,7 +1224,7 @@ class CookieSyncSpec extends BaseSpec { def uidsCookie = UidsCookie.defaultUidsCookie when: "PBS processes cookie sync request with uids cookies" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest, uidsCookie) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest, uidsCookie) then: "Response should have status 'OK'" assert response.status == OK @@ -1691,8 +1233,7 @@ class CookieSyncSpec extends BaseSpec { assert !response?.getBidderUserSync(GENERIC) and: "Response should contain configured bidders" - assert response?.getBidderStatus()?.bidder?.sort() == - [MAGNITE, APPNEXUS, OPENX, ACEEX, ACUITYADS, AAX, ADKERNEL].sort() + assert response?.getBidderStatus()?.bidder?.sort() == (DEFAULT_PBS_BIDDERS - GENERIC).sort() } def "PBS cookie sync request shouldn't return iframe sync url included by sync type bidders for bidder in cookie"() { @@ -1757,15 +1298,14 @@ class CookieSyncSpec extends BaseSpec { def cookieSyncRequest = new CookieSyncRequest(bidders: null, coopSync: true) when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should have status 'NO_COOKIE'" assert response.status == NO_COOKIE and: "Response should contain coop sync bidders" - assert response.bidderStatus.size() == DEFAULT_PBS_BIDDERS_SIZE + assert response.bidderStatus.size() == DEFAULT_PBS_BIDDERS.size() assert response.getBidderUserSync(AAX) - assert response.getBidderUserSync(ACUITYADS) assert response.getBidderUserSync(ADKERNEL) assert response.getBidderUserSync(OPENX) assert response.getBidderUserSync(GENERIC) @@ -1775,19 +1315,14 @@ class CookieSyncSpec extends BaseSpec { } def "PBS cookie sync request should contain request bidders and rest from coop sync"() { - given: "PBS config with expanded limit" - def defaultSyncLimit = 3 - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.default-limit": defaultSyncLimit as String] + PBS_CONFIG) - - and: "Default cookie sync request" + given: "Default cookie sync request" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { bidders = [APPNEXUS, GENERIC] coopSync = true } when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should have status 'NO_COOKIE'" assert response.status == NO_COOKIE @@ -1799,12 +1334,7 @@ class CookieSyncSpec extends BaseSpec { } def "PBS cookie sync request should contain only request bidders when coop sync off"() { - given: "PBS config with expanded limit" - def defaultSyncLimit = 3 - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.default-limit": defaultSyncLimit as String] + PBS_CONFIG) - - and: "Default cookie sync request" + given: "Default cookie sync request" def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { bidders = [APPNEXUS, GENERIC] coopSync = false @@ -1928,13 +1458,13 @@ class CookieSyncSpec extends BaseSpec { } when: "PBS processes cookie sync request without cookies" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should have status 'NO_COOKIE'" assert response.status == NO_COOKIE and: "Response should contain eight bidder by default" - assert response?.getBidderStatus()?.size() == DEFAULT_PBS_BIDDERS_SIZE + assert response?.getBidderStatus()?.size() == DEFAULT_PBS_BIDDERS.size() } def "PBS cookie sync request should limit the number of returned bidders"() { @@ -1977,21 +1507,21 @@ class CookieSyncSpec extends BaseSpec { } when: "PBS processes cookie sync request without cookies" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should contains all available coop sync bidders" - assert response.bidderStatus.bidder.size() == DEFAULT_PBS_BIDDERS_SIZE + assert response.bidderStatus.bidder.size() == DEFAULT_PBS_BIDDERS.size() } def "PBS cookie sync request should override general configuration limit"() { given: "Cookie sync request body" def cookieSyncRequest = new CookieSyncRequest().tap { it.coopSync = true - it.limit = PBSUtils.getRandomNumber(1, DEFAULT_PBS_BIDDERS_SIZE) + it.limit = PBSUtils.getRandomNumber(1, DEFAULT_PBS_BIDDERS.size()) } when: "PBS processes cookie sync request without cookies" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should contains same count of bidder as specified limit" assert response.bidderStatus.size() == cookieSyncRequest.limit @@ -2163,33 +1693,6 @@ class CookieSyncSpec extends BaseSpec { null | 1 } - def "PBS cookie sync request should take precedence request limit over account and global config"() { - given: "PBS config with expanded limit" - def prebidServerService = pbsServiceFactory.getService( - ["cookie-sync.default-limit": "3"] + PBS_CONFIG) - - and: "Default cookie sync request" - def accountId = PBSUtils.randomNumber - def cookieSyncRequest = CookieSyncRequest.defaultCookieSyncRequest.tap { - bidders = [GENERIC, BOGUS] - account = accountId - limit = 1 - debug = false - } - - and: "Save account with cookie config" - def cookieSyncConfig = new AccountCookieSyncConfig(defaultLimit: 2) - def accountConfig = new AccountConfig(status: ACTIVE, cookieSync: cookieSyncConfig) - def account = new Account(uuid: accountId, config: accountConfig) - accountDao.save(account) - - when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) - - then: "Response should contain corresponding bidders size due to request limit" - assert response.bidderStatus.size() == cookieSyncRequest.limit - } - def "PBS cookie sync request should take presence coop sync over coop sync in config"() { given: "Default cookie sync request" def accountId = PBSUtils.randomNumber @@ -2205,10 +1708,10 @@ class CookieSyncSpec extends BaseSpec { accountDao.save(account) when: "PBS processes cookie sync request" - def response = prebidServerService.sendCookieSyncRequest(cookieSyncRequest) + def response = pbsWithoutLimitService.sendCookieSyncRequest(cookieSyncRequest) then: "Response should contain corresponding bidders size due to global config" - assert response.bidderStatus.size() == 9 + assert response.bidderStatus.size() == (DEFAULT_PBS_BIDDERS + BOGUS).size() where: cookieSyncConfig << [new AccountCookieSyncConfig(coopSync: new AccountCoopSyncConfig(enabled: true)), diff --git a/src/test/groovy/org/prebid/server/functional/tests/CurrencySpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CurrencySpec.groovy index 662f9423848..47044a04719 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CurrencySpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CurrencySpec.groovy @@ -4,6 +4,7 @@ import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.PbsConfig +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.testcontainers.scaffolding.CurrencyConversion import org.prebid.server.functional.util.CurrencyUtil @@ -18,12 +19,17 @@ import static org.prebid.server.functional.util.CurrencyUtil.DEFAULT_CURRENCY class CurrencySpec extends BaseSpec { + private static final PbsContainerConfig PBS_CONFIG = new PbsContainerConfig(PbsConfig.currencyConverterConfig) private static final CurrencyConversion currencyConversion = new CurrencyConversion(networkServiceContainer) private static PrebidServerService pbsService def setupSpec() { currencyConversion.setCurrencyConversionRatesResponse() - pbsService = pbsServiceFactory.getService(PbsConfig.currencyConverterConfig) + pbsService = pbsServiceFactory.getService(PBS_CONFIG) + } + + def cleanupSpec() { + pbsServiceFactory.removeContainer(PBS_CONFIG) } def "PBS should return currency rates"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/HttpSettingsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/HttpSettingsSpec.groovy index bdf1d453fe8..8e3f1f9b8bb 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/HttpSettingsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/HttpSettingsSpec.groovy @@ -216,9 +216,6 @@ class HttpSettingsSpec extends BaseSpec { and: "There should be only one account request" assert httpSettings.getRequestCount(request.account) == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should take account information from http data source on setuid request when rfc3986 enabled"() { @@ -251,9 +248,6 @@ class HttpSettingsSpec extends BaseSpec { and: "There should be only one account request" assert httpSettingsWithRfc.getRfcRequestCount(request.account) == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should take account information from http data source on vtrack request"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy index 4e0253c1f95..8be9db2a837 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy @@ -6,6 +6,7 @@ import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED import static org.prebid.server.functional.testcontainers.Dependencies.influxdbContainer @@ -14,7 +15,7 @@ class InfluxDBSpec extends BaseSpec { private static final String ACCOUNT_REJECTED_METRIC = "influx.metric.account.%s.requests.rejected.invalid-account" - private static final Map PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT = [ + private static final PbsContainerConfig PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT = new PbsContainerConfig([ "metrics.influxdb.enabled" : "true", "metrics.influxdb.prefix" : "influx.metric.", "metrics.influxdb.host" : influxdbContainer.getNetworkAliases().get(0), @@ -25,7 +26,7 @@ class InfluxDBSpec extends BaseSpec { "metrics.influxdb.interval" : "1", "metrics.influxdb.connectTimeout": "5000", "metrics.influxdb.readTimeout" : "100", - "settings.enforce-valid-account": true as String] + "settings.enforce-valid-account": true as String]) private static final PrebidServerService pbsServiceWithEnforceValidAccount = pbsServiceFactory.getService(PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT) diff --git a/src/test/groovy/org/prebid/server/functional/tests/ProfileSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/ProfileSpec.groovy index dd3b49efcc1..ac064231128 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/ProfileSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/ProfileSpec.groovy @@ -32,9 +32,9 @@ import org.prebid.server.functional.repository.dao.ProfileImpDao import org.prebid.server.functional.repository.dao.ProfileRequestDao import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService -import org.prebid.server.functional.testcontainers.container.PrebidServerContainer +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig +import org.prebid.server.functional.util.ContainerFileUtil import org.prebid.server.functional.util.PBSUtils -import org.testcontainers.images.builder.Transferable import spock.lang.PendingFeature import static org.prebid.server.functional.model.AccountStatus.ACTIVE @@ -82,7 +82,6 @@ class ProfileSpec extends BaseSpec { private static final ProfileImpDao profileImpDao = repository.profileImpDao private static final ProfileRequestDao profileRequestDao = repository.profileRequestDao - private static PrebidServerContainer pbsContainer private static PrebidServerService pbsWithStoredProfiles private static RequestProfile fileRequestProfile private static RequestProfile fileRequestProfileWithEmptyMerge @@ -90,11 +89,8 @@ class ProfileSpec extends BaseSpec { private static ImpProfile fileImpProfileWithEmptyMerge def setupSpec() { - pbsContainer = new PrebidServerContainer(FILESYSTEM_CONFIG + PROFILES_CONFIG) fileRequestProfile = RequestProfile.getProfile(ACCOUNT_ID_FILE_STORAGE.toString()) fileImpProfile = ImpProfile.getProfile(ACCOUNT_ID_FILE_STORAGE.toString()) - pbsContainer.withCopyToContainer(Transferable.of(encode(fileRequestProfile)), "$PROFILES_PATH/${fileRequestProfile.fileName}") - pbsContainer.withCopyToContainer(Transferable.of(encode(fileImpProfile)), "$PROFILES_PATH/${fileImpProfile.fileName}") fileRequestProfileWithEmptyMerge = RequestProfile.getProfile(ACCOUNT_ID_FILE_STORAGE.toString()).tap { mergePrecedence = null } @@ -105,21 +101,16 @@ class ProfileSpec extends BaseSpec { } mergePrecedence = null } - pbsContainer.withCopyToContainer(Transferable.of(encode(fileRequestProfileWithEmptyMerge)), "$PROFILES_PATH/${fileRequestProfileWithEmptyMerge.fileName}") - pbsContainer.withCopyToContainer(Transferable.of(encode(fileImpProfileWithEmptyMerge)), "$PROFILES_PATH/${fileImpProfileWithEmptyMerge.fileName}") - pbsContainer.withFolder(REQUESTS_PATH) - pbsContainer.withFolder(IMPS_PATH) - pbsContainer.withFolder(RESPONSES_PATH) - pbsContainer.withFolder(CATEGORIES_PATH) def accountsConfig = new FileSystemAccountsConfig(accounts: [new AccountConfig(id: ACCOUNT_ID_FILE_STORAGE, status: ACTIVE)]) - pbsContainer.withCopyToContainer(Transferable.of(encodeYaml(accountsConfig)), - SETTINGS_FILENAME) - pbsContainer.start() - pbsWithStoredProfiles = new PrebidServerService(pbsContainer) - } - - def cleanupSpec() { - pbsContainer.stop() + def folders = ContainerFileUtil.emptyFolders( + REQUESTS_PATH, IMPS_PATH, RESPONSES_PATH, CATEGORIES_PATH) + def profiles = [fileRequestProfile, fileImpProfile, fileRequestProfileWithEmptyMerge, fileImpProfileWithEmptyMerge] + .collectEntries { profile -> + ContainerFileUtil.jsonFile("$PROFILES_PATH/${profile.fileName}", profile) + } + def accountsFile = ContainerFileUtil.yamlFile(SETTINGS_FILENAME, accountsConfig) + def files = folders + profiles + accountsFile + pbsWithStoredProfiles = pbsServiceFactory.getService(new PbsContainerConfig(FILESYSTEM_CONFIG + PROFILES_CONFIG, files)) } def "PBS should use profile for request when it exist in database"() { @@ -934,9 +925,6 @@ class ProfileSpec extends BaseSpec { def exception = thrown(PrebidServerException) assert exception.statusCode == 400 assert exception.responseBody == INVALID_REQUEST_PREFIX + NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(PROFILES_CONFIG + ['auction.profiles.fail-on-unknown': 'true']) } def "PBS should fail auction when fail-on-unknown-profile default and profile is missing"() { @@ -960,9 +948,6 @@ class ProfileSpec extends BaseSpec { def exception = thrown(PrebidServerException) assert exception.statusCode == 400 assert exception.responseBody == INVALID_REQUEST_PREFIX + NO_IMP_PROFILE_MESSAGE.formatted(invalidProfileId) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(PROFILES_CONFIG + ['auction.profiles.fail-on-unknown': null]) } def "PBS should prioritise fail-on-unknown-profile from account over host config"() { @@ -1522,35 +1507,19 @@ class ProfileSpec extends BaseSpec { ] } - def "PBS should throw exception when profiles are not configured for filesystem and request contain profileId"() { - given: "PBS with profiles.fail-on-unknown config" - def config = FILESYSTEM_CONFIG + PROFILES_CONFIG + ['settings.filesystem.profiles-dir': null] - pbsContainer = new PrebidServerContainer(config) - pbsContainer.withFolder(REQUESTS_PATH) - pbsContainer.withFolder(IMPS_PATH) - pbsContainer.withFolder(RESPONSES_PATH) - pbsContainer.withFolder(CATEGORIES_PATH) - def accountsConfig = new FileSystemAccountsConfig(accounts: [new AccountConfig(id: ACCOUNT_ID_FILE_STORAGE, status: ACTIVE)]) - pbsContainer.withCopyToContainer(Transferable.of(encodeYaml(accountsConfig)), - SETTINGS_FILENAME) - pbsContainer.start() - pbsWithStoredProfiles = new PrebidServerService(pbsContainer) - - and: "BidRequest with profile" + def "PBS should throw exception when profiles are not configured for filesystem and request contains profileId"() { + given: "BidRequest with profile" def requestWithProfile = BidRequest.getDefaultBidRequest().tap { - it.ext.prebid.profileNames = [PBSUtils.randomString] + ext.prebid.profileNames = [PBSUtils.randomString] } when: "PBS processes auction request" defaultPbsService.sendAuctionRequest(requestWithProfile) - then: "PBs should throw error due to invalid profile config" + then: "PBS should throw error due to invalid profile config" def exception = thrown(PrebidServerException) assert exception.statusCode == 400 assert exception.responseBody == INVALID_REQUEST_PREFIX + CONFIG_ERROR_MESSAGE - - cleanup: "Stop and remove pbs container" - pbsContainer.stop() } private static BidRequest getRequestWithProfiles(String accountId, List profiles) { diff --git a/src/test/groovy/org/prebid/server/functional/tests/SecondaryBidderSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/SecondaryBidderSpec.groovy index 706e5a9d648..3c070d87a91 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/SecondaryBidderSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/SecondaryBidderSpec.groovy @@ -9,6 +9,7 @@ import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.testcontainers.scaffolding.Bidder import org.prebid.server.functional.util.PBSUtils import spock.lang.Shared @@ -31,17 +32,18 @@ class SecondaryBidderSpec extends BaseSpec { "adapters.${GENERIC.value}.aliases.${ALIAS}.enabled" : "true", "adapters.${GENERIC.value}.aliases.${ALIAS}.meta-info.vendor-id": "0", "adapters.${GENERIC.value}.aliases.${ALIAS}.endpoint" : "$networkServiceContainer.rootUri$GENERIC_ALIAS_AUCTION_ENDPOINT".toString()] + private static final PbsContainerConfig PBS_CONFIG = new PbsContainerConfig(OPENX_CONFIG + GENERIC_ALIAS_CONFIG) private static final Integer RESPONSE_DELAY_MILLISECONDS = 5_000 private static final Bidder openXBidder = new Bidder(networkServiceContainer, OPENX_AUCTION_ENDPOINT) private static final Bidder genericAliasBidder = new Bidder(networkServiceContainer, GENERIC_ALIAS_AUCTION_ENDPOINT) private static final String WARNING_TIME_OUT_MESSAGE = "secondary bidder timed out, auction proceeded" - private static final PrebidServerService pbsServiceWithOpenXBidder = pbsServiceFactory.getService(OPENX_CONFIG + GENERIC_ALIAS_CONFIG) + private static final PrebidServerService pbsServiceWithOpenXBidder = pbsServiceFactory.getService(PBS_CONFIG) @Override def cleanupSpec() { - pbsServiceFactory.removeContainer(OPENX_CONFIG + GENERIC_ALIAS_CONFIG) + pbsServiceFactory.removeContainer(PBS_CONFIG) } def setup() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy index d14d58c3f61..ecc5f20633c 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy @@ -160,9 +160,6 @@ class SetUidSpec extends BaseSpec { then: "Response should contain requested tempUIDs" assert response.uidsCookie.tempUIDs[GENERIC] assert response.uidsCookie.tempUIDs[MAGNITE] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should return prioritized uids bidder when size is full"() { @@ -188,9 +185,6 @@ class SetUidSpec extends BaseSpec { then: "Response should contain uids cookies" assert response.uidsCookie.tempUIDs[magniteBidder] assert response.uidsCookie.tempUIDs[genericBidder] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should remove most distant expiration bidder when size is full"() { @@ -219,9 +213,6 @@ class SetUidSpec extends BaseSpec { then: "Response should contain uids cookies" assert response.uidsCookie.tempUIDs[MAGNITE] assert response.uidsCookie.tempUIDs[GENERIC] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should ignore requested bidder and log metric when cookie's filled and requested bidder not in prioritize list"() { @@ -251,9 +242,6 @@ class SetUidSpec extends BaseSpec { and: "Response should contain uids cookies" assert response.uidsCookie.tempUIDs[APPNEXUS] assert response.uidsCookie.tempUIDs[MAGNITE] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should reject bidder when cookie's filled and requested bidder in pri and rejected by tcf"() { @@ -284,9 +272,6 @@ class SetUidSpec extends BaseSpec { and: "usersync.BIDDER.tcf.blocked metric should be updated" def metric = prebidServerService.sendCollectedMetricsRequest() assert metric["usersync.${MAGNITE.value}.tcf.blocked"] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should remove most distant expiration uid and log metric when cookie's filled and this uid's not on the pri"() { @@ -317,9 +302,6 @@ class SetUidSpec extends BaseSpec { then: "Response should contain uids cookies" assert response.uidsCookie.tempUIDs[APPNEXUS] assert response.uidsCookie.tempUIDs[GENERIC] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS set uid should emit sizeblocked metric and remove most distant expiration bidder from uids cookie for non-prioritized bidder"() { @@ -360,9 +342,6 @@ class SetUidSpec extends BaseSpec { and: "usersync.BIDDER.sets metric should be updated" assert metricsRequest["usersync.${OPENX.value}.sets"] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS set uid should emit sizedout metric and remove most distant expiration bidder from uids cookie in prioritized bidder"() { @@ -396,9 +375,6 @@ class SetUidSpec extends BaseSpec { and: "usersync.FAMILY.sizedout metric should be updated" def metricsRequest = prebidServerService.sendCollectedMetricsRequest() assert metricsRequest["usersync.${APPNEXUS.value}.sizedout"] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should reject request when requested bidder mismatching with cookie-family-name"() { @@ -499,9 +475,6 @@ class SetUidSpec extends BaseSpec { then: "Response should contain requested tempUIDs" assert response.uidsCookie.tempUIDs.keySet() == new LinkedHashSet([GENERIC, OPENX, APPNEXUS, MAGNITE]) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should remove duplicates when incoming cookie-family already exists in the working list"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/TargetingSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/TargetingSpec.groovy index 008f4c6a721..51c65f5b5af 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/TargetingSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/TargetingSpec.groovy @@ -35,6 +35,7 @@ import org.prebid.server.functional.model.response.auction.SeatBid import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.PbsConfig +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.testcontainers.scaffolding.Bidder import org.prebid.server.functional.util.PBSUtils @@ -65,9 +66,9 @@ class TargetingSpec extends BaseSpec { private static final String EMPTY_CPM = "0.0" private static final Integer DEFAULT_TRUNCATE_CHARS = 20 private static final Integer EXTENDED_TRUNCATE_CHARS = PbsConfig.targetingConfig.get('settings.targeting.truncate-attr-chars').toInteger() - private static final Map EMPTY_TARGETING_CONFIG = ['settings.targeting.truncate-attr-chars': null] as Map - private static final Map ONLY_WINNING_BIDS_CONFIG = ["auction.cache.only-winning-bids": "true"] - private static final Map DISABLED_ONLY_WINNING_BIDS_CONFIG = ["auction.cache.only-winning-bids": "false"] + private static final PbsContainerConfig EMPTY_TARGETING_CONFIG = new PbsContainerConfig(['settings.targeting.truncate-attr-chars': null]) + private static final PbsContainerConfig ONLY_WINNING_BIDS_CONFIG = new PbsContainerConfig(["auction.cache.only-winning-bids": "true"]) + private static final PbsContainerConfig DISABLED_ONLY_WINNING_BIDS_CONFIG = new PbsContainerConfig(["auction.cache.only-winning-bids": "false"]) private static final String DROP_PREFIX_WARNING = "Key prefix value is dropped to default. " + "Decrease custom prefix length or increase truncateattrchars by %s" private static final String TRUNCATED_WARNING = "The following keys have been truncated:" @@ -429,9 +430,9 @@ class TargetingSpec extends BaseSpec { def "PBS should auction populate ext.prebid.targeting with proper size when truncateTargetAttr is define"() { given: "PBs config with additional openx bidder" - def pbsConfig = [ + def pbsConfig = new PbsContainerConfig([ "adapters.openx.enabled" : "true", - "adapters.openx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + "adapters.openx.endpoint": "$networkServiceContainer.rootUri/auction".toString()]) def pbsWithDefaultTargetingLength = pbsServiceFactory.getService(pbsConfig) and: "Default bid request" @@ -460,9 +461,6 @@ class TargetingSpec extends BaseSpec { and: "Bidder request should contain ext.prebid.adservertargeting" def bidderRequest = bidder.getBidderRequests(bidRequest.id) assert bidderRequest.ext.prebid.targeting - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should truncate targeting corresponding to value in account config when in account define truncate target attr"() { @@ -1281,7 +1279,7 @@ class TargetingSpec extends BaseSpec { def accountConfig = new AccountConfig(status: ACTIVE, auction: accountAuctionConfig) and: "PBS with default account" - def pbsConfig = ["settings.default-account-config": encode(accountConfig)] + def pbsConfig = new PbsContainerConfig(["settings.default-account-config": encode(accountConfig)]) def pbsService = pbsServiceFactory.getService(pbsConfig) and: "Default basic BidRequest" @@ -1295,9 +1293,6 @@ class TargetingSpec extends BaseSpec { then: "BidderRequest should include price granularity from account config" def bidderRequest = bidder.getBidderRequest(bidRequest.id) assert bidderRequest?.ext?.prebid?.targeting?.priceGranularity == PriceGranularity.getDefault(priceGranularity) - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS auction should include include default price granularity when original request and account config doesn't contain price granularity"() { @@ -1632,8 +1627,8 @@ class TargetingSpec extends BaseSpec { def "PBS should assign bid ranks across all seatbids combined when the request contains imps with multiple bidders"() { given: "PBS config with openX bidder" def endpoint = '/openx-auction' - def pbsConfig = ["adapters.openx.enabled" : "true", - "adapters.openx.endpoint": "$networkServiceContainer.rootUri$endpoint".toString()] + def pbsConfig = new PbsContainerConfig(["adapters.openx.enabled" : "true", + "adapters.openx.endpoint": "$networkServiceContainer.rootUri$endpoint".toString()]) def prebidServerService = pbsServiceFactory.getService(pbsConfig) def openxBidder = new Bidder(networkServiceContainer, endpoint) diff --git a/src/test/groovy/org/prebid/server/functional/tests/TimeoutSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/TimeoutSpec.groovy index cff45989db1..2d534ab1f54 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/TimeoutSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/TimeoutSpec.groovy @@ -5,12 +5,14 @@ import org.prebid.server.functional.model.request.amp.AmpRequest import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.PrebidStoredRequest import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.testcontainers.container.PrebidServerContainer import org.prebid.server.functional.util.PBSUtils import org.testcontainers.utility.MountableFile import spock.lang.Shared import static org.prebid.server.functional.testcontainers.container.PrebidServerContainer.APP_WORKDIR +import static org.prebid.server.functional.util.ContainerFileUtil.* class TimeoutSpec extends BaseSpec { @@ -18,8 +20,8 @@ class TimeoutSpec extends BaseSpec { private static final int MIN_TIMEOUT = PBSUtils.getRandomNumber(50, 150) private static final Long MAX_AUCTION_BIDDER_TIMEOUT = 3000 private static final Long MIN_AUCTION_BIDDER_TIMEOUT = 1000 - private static final Map PBS_CONFIG = ["auction.biddertmax.max": MAX_AUCTION_BIDDER_TIMEOUT as String, - "auction.biddertmax.min": MIN_AUCTION_BIDDER_TIMEOUT as String] + private static final PbsContainerConfig PBS_CONFIG = new PbsContainerConfig(["auction.biddertmax.max": MAX_AUCTION_BIDDER_TIMEOUT as String, + "auction.biddertmax.min": MIN_AUCTION_BIDDER_TIMEOUT as String]) @Shared PrebidServerService prebidServerService = pbsServiceFactory.getService(PBS_CONFIG) @@ -131,19 +133,15 @@ class TimeoutSpec extends BaseSpec { assert isInternalProcessingTime(bidderRequest.tmax, MAX_TIMEOUT) } + def "PBS should take data by priority when request, stored request, default request are defined"() { - given: "Default request with timeout" - def defaultRequestModel = new BidRequest(tmax: defaultRequestTmax) - def defaultRequest = PBSUtils.createJsonFile(defaultRequestModel) - - and: "Pbs config with default request" - def pbsContainer = new PrebidServerContainer( - ["default-request.file.path": APP_WORKDIR + defaultRequest.fileName, - "auction.biddertmax.max" : MAX_TIMEOUT as String]).tap { - withCopyFileToContainer(MountableFile.forHostPath(defaultRequest), APP_WORKDIR) - } - pbsContainer.start() - def pbsService = new PrebidServerService(pbsContainer) + given: "PBS service with default request" + def defaultRequestPath = APP_WORKDIR + 'default-request.json' + def defaultRequest = new BidRequest(tmax: defaultRequestTmax) + def pbsConfig = new PbsContainerConfig(['default-request.file.path': defaultRequestPath, + 'auction.biddertmax.max' : MAX_TIMEOUT.toString()], + jsonFile(defaultRequestPath, defaultRequest)) + def pbsService = pbsServiceFactory.getService(pbsConfig) and: "Default basic BidRequest with timeout" def bidRequest = BidRequest.defaultBidRequest.tap { @@ -156,24 +154,21 @@ class TimeoutSpec extends BaseSpec { tmax = storedRequestTmax as Long } - and: "Save storedRequest into DB" + and: "Save stored request into DB" def storedRequest = StoredRequest.getStoredRequest(bidRequest.ext.prebid.storedRequest.id, storedRequestModel) storedRequestDao.save(storedRequest) when: "PBS processes auction request with warmup" def response = pbsService.withWarmup().sendAuctionRequest(bidRequest) - then: "Response should not contain error" + then: "Response should not contain errors or warnings" assert !response.ext?.errors assert !response.ext?.warnings - then: "Bidder request should contain correct tmax" + and: "Bidder request should contain correct tmax" def bidderRequest = bidder.getBidderRequest(bidRequest.id) assert isInternalProcessingTime(bidderRequest.tmax, DEFAULT_TIMEOUT) - cleanup: "Stop container with default request" - pbsContainer.stop() - where: requestTmax | storedRequestTmax | defaultRequestTmax DEFAULT_TIMEOUT | getRandomTimeout() | getRandomTimeout() @@ -311,9 +306,9 @@ class TimeoutSpec extends BaseSpec { def "PBS should change timeout for bidder due to percent in auction.biddertmax.percent"() { given: "PBS config with percent" def percent = PBSUtils.getRandomNumber(2, 98) - def pbsConfig = ["auction.biddertmax.percent": percent as String, - "auction.biddertmax.max" : MAX_TIMEOUT as String, - "auction.biddertmax.min" : MIN_TIMEOUT as String] + def pbsConfig = new PbsContainerConfig(["auction.biddertmax.percent": percent as String, + "auction.biddertmax.max" : MAX_TIMEOUT as String, + "auction.biddertmax.min" : MIN_TIMEOUT as String]) def prebidServerService = pbsServiceFactory.getService( pbsConfig) @@ -332,14 +327,11 @@ class TimeoutSpec extends BaseSpec { and: "PBS response should contain tmax from request" assert bidResponse?.ext?.tmaxrequest == timeout as Long - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should apply auction.biddertmax.max timeout when adapters.generic.tmax-deduction-ms exceeds valid top range"() { given: "PBS config with adapters.generic.tmax-deduction-ms" - def pbsConfig = PBS_CONFIG + ["adapters.generic.tmax-deduction-ms": PBSUtils.getRandomNumber(MAX_AUCTION_BIDDER_TIMEOUT as int) as String] + def pbsConfig = PBS_CONFIG + ["adapters.generic.tmax-deduction-ms": PBSUtils.getRandomNumber(MAX_AUCTION_BIDDER_TIMEOUT as int)] def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Default basic BidRequest with generic bidder" @@ -356,14 +348,11 @@ class TimeoutSpec extends BaseSpec { and: "PBS response should contain tmax" assert bidResponse?.ext?.tmaxrequest == MAX_AUCTION_BIDDER_TIMEOUT - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should resolve timeout as usual when adapters.generic.tmax-deduction-ms specifies zero"() { given: "PBS config with adapters.generic.tmax-deduction-ms" - def pbsConfig = ["adapters.generic.tmax-deduction-ms": "0"] + PBS_CONFIG + def pbsConfig = PBS_CONFIG + ["adapters.generic.tmax-deduction-ms": "0"] def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Default basic BidRequest with generic bidder" @@ -383,9 +372,6 @@ class TimeoutSpec extends BaseSpec { and: "PBS response should contain tmax" assert bidResponse?.ext?.tmaxrequest == timeout as Long - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should properly resolve tmax deduction ms when adapters.generic.tmax-deduction-ms specified"() { @@ -409,9 +395,6 @@ class TimeoutSpec extends BaseSpec { and: "PBS response should contain tmax" assert bidResponse?.ext?.tmaxrequest == randomTimeout as Long - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } private static long getPercentOfValue(int percent, int value) { diff --git a/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderConfigurationSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderConfigurationSpec.groovy new file mode 100644 index 00000000000..6f5e12c6bab --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderConfigurationSpec.groovy @@ -0,0 +1,248 @@ +package org.prebid.server.functional.tests.bidder + +import org.prebid.server.functional.model.bidder.Generic +import org.prebid.server.functional.model.config.Endpoint +import org.prebid.server.functional.model.db.Account +import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.model.request.auction.Device +import org.prebid.server.functional.model.request.auction.Geo +import org.prebid.server.functional.model.request.vtrack.VtrackRequest +import org.prebid.server.functional.model.request.vtrack.xml.Vast +import org.prebid.server.functional.tests.BaseSpec +import org.prebid.server.functional.util.PBSUtils +import org.prebid.server.functional.util.privacy.CcpaConsent + +import static org.prebid.server.functional.model.bidder.BidderName.ALIAS +import static org.prebid.server.functional.model.bidder.BidderName.GENER_X +import static org.prebid.server.functional.model.bidder.CompressionType.GZIP +import static org.prebid.server.functional.model.bidder.CompressionType.NONE +import static org.prebid.server.functional.model.response.auction.ErrorType.GENERIC +import static org.prebid.server.functional.util.HttpUtil.CONTENT_ENCODING_HEADER +import static org.prebid.server.functional.util.privacy.CcpaConsent.Signal.ENFORCED + +class BidderConfigurationSpec extends BaseSpec { + + private static final Map DISABLE_INVALID_BIDDER_CONFIGS = [ + "adapters.audiencenetwork.enabled": "false", + "adapters.adxcg.enabled" : "false", + "adapters.avocet.enabled" : "false", + "adapters.pangle.enabled" : "false", + "adapters.teqblaze.enabled" : "false", + "adapters.ix.enabled" : "false" + ] + + private static final Map BIDDER_CONFIG = [ + "adapters.${GENERIC.value}.enabled" : true, + "adapters.${GENERIC.value}.meta-info.vendor-id" : 0, + + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.enabled" : true, + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.meta-info.vendor-id" : 0, + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.modifying-vast-xml-allowed" : true, + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.pbs-enforces-ccpa" : true, + + "adapters.${GENERIC.value}.aliases.${GENER_X.value}.enabled" : "true", + "adapters.${GENERIC.value}.aliases.${GENER_X.value}.meta-info.vendor-id" : "0", + "adapters.${GENERIC.value}.aliases.${GENER_X.value}.modifying-vast-xml-allowed": "false", + "adapters.${GENERIC.value}.aliases.${GENER_X.value}.pbs-enforces-ccpa" : "false" + ] + + private static final Map ENABLED_DEFAULTS_CONFIG = BIDDER_CONFIG + [ + "adapter-defaults.enabled" : "true", + "adapter-defaults.modifying-vast-xml-allowed": "true", + "adapter-defaults.pbs-enforces-ccpa" : "true", + "adapters.generic.endpoint-compression" : GZIP.value + ] + DISABLE_INVALID_BIDDER_CONFIGS + + private static final Map DISABLED_DEFAULTS_CONFIG = BIDDER_CONFIG + [ + "adapter-defaults.enabled" : "false", + "adapter-defaults.modifying-vast-xml-allowed": "false", + "adapter-defaults.pbs-enforces-ccpa" : "false", + "adapters.generic.endpoint-compression" : NONE.value + ] + + private static final Map BIDDER_DISABLED_DEFAULTS_ENABLED_CONFIG = [ + "adapter-defaults.enabled": "true", + "adapters.generic.enabled": "false" + ] + DISABLE_INVALID_BIDDER_CONFIGS + + private static final Map BIDDER_DISABLED_DEFAULTS_DISABLED_CONFIG = [ + "adapter-defaults.enabled": "false", + "adapters.generic.enabled": "false" + ] + + private static final enabledDefaultService = pbsServiceFactory.getService(ENABLED_DEFAULTS_CONFIG) + private static final disabledDefaultService = pbsServiceFactory.getService(DISABLED_DEFAULTS_CONFIG) + + def "PBS should reject disabled generic bidder regardless of adapter defaults"() { + given: "PBS with disabled generic bidder" + def pbsService = pbsServiceFactory.getService(pbsConfig) + def bidRequest = BidRequest.defaultBidRequest + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response contains bidder error" + assert response.ext?.errors[GENERIC]*.code == [2] + + where: + pbsConfig << [BIDDER_DISABLED_DEFAULTS_ENABLED_CONFIG, BIDDER_DISABLED_DEFAULTS_DISABLED_CONFIG] + } + + def "PBS should call enabled generic bidder regardless of adapter defaults"() { + given: "Default bidRequest" + def bidRequest = BidRequest.defaultBidRequest + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Bidder is called" + assert response.ext?.debug?.httpcalls[GENERIC.value] + + and: "Response has no errors" + assert !response.ext?.errors + + where: + pbsService << [enabledDefaultService, disabledDefaultService] + } + + def "PBS should modify VAST XML when bidder allows modification regardless of adapter defaults"() { + given: "Vtrack request for alias" + def payload = PBSUtils.randomString + def request = VtrackRequest.getDefaultVtrackRequest(encodeXml(Vast.getDefaultVastModel(payload))).tap { + puts[0].bidder = ALIAS.value + } + def accountId = PBSUtils.randomNumber + + and: "Account in DB" + accountDao.save(new Account(uuid: accountId, eventsEnabled: true)) + + when: "PBS processes vtrack request" + pbsService.sendPostVtrackRequest(request, accountId.toString()) + + then: "Cached VAST contains impression tracking" + def cachedVast = prebidCache.getXmlRecordedRequestsBody(payload) + assert cachedVast.size() == 1 + assert cachedVast.first().contains("${Endpoint.EVENT}?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}") + + where: + pbsService << [enabledDefaultService, disabledDefaultService] + } + + def "PBS should preserve VAST XML when bidder disallows modification regardless of adapter defaults"() { + given: "Vtrack request for alias" + def payload = PBSUtils.randomString + def request = VtrackRequest.getDefaultVtrackRequest(encodeXml(Vast.getDefaultVastModel(payload))).tap { + puts[0].bidder = GENER_X.value + } + def accountId = PBSUtils.randomNumber + + and: "Account in DB" + accountDao.save(new Account(uuid: accountId, eventsEnabled: true)) + + when: "PBS processes vtrack request" + pbsService.sendPostVtrackRequest(request, accountId.toString()) + + then: "Cached VAST does not contain impression tracking" + def cachedVast = prebidCache.getXmlRecordedRequestsBody(payload) + assert cachedVast.size() == 1 + assert !cachedVast.first().contains("${Endpoint.EVENT}?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}") + + where: + pbsService << [enabledDefaultService, disabledDefaultService] + } + + def "PBS should mask CCPA-sensitive geo for bidder with CCPA enforcement enabled"() { + given: "Bid request with CCPA consent and geo" + def lat = PBSUtils.getRandomDecimal(0, 90) + def lon = PBSUtils.getRandomDecimal(0, 90) + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.alias = new Generic() + regs.usPrivacy = new CcpaConsent(explicitNotice: ENFORCED, optOutSale: ENFORCED) + device = new Device(geo: new Geo(lat: lat, lon: lon)) + } + + when: "PBS processes auction request" + pbsService.sendAuctionRequest(bidRequest) + + then: "Bidder receives masked coordinates" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.device?.geo?.lat as BigDecimal == PBSUtils.roundDecimal(lat, 2) + assert bidderRequest.device?.geo?.lon as BigDecimal == PBSUtils.roundDecimal(lon, 2) + + where: + pbsService << [enabledDefaultService, disabledDefaultService] + } + + def "PBS should preserve CCPA-sensitive geo for bidder with CCPA enforcement disabled"() { + given: "Bid request with CCPA consent and geo" + def lat = PBSUtils.getRandomDecimal(0, 90) as float + def lon = PBSUtils.getRandomDecimal(0, 90) as float + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.generX = new Generic() + regs.usPrivacy = new CcpaConsent(explicitNotice: ENFORCED, optOutSale: ENFORCED) + device = new Device(geo: new Geo(lat: lat, lon: lon)) + } + + when: "PBS processes auction request" + pbsService.sendAuctionRequest(bidRequest) + + then: "Bidder receives original coordinates" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.device?.geo?.lat == lat + assert bidderRequest.device?.geo?.lon == lon + + where: + pbsService << [enabledDefaultService, disabledDefaultService] + } + + def "PBS should gzip bidder request when endpoint compression is gzip"() { + given: "Default bidRequest" + def bidRequest = BidRequest.defaultBidRequest + + when: "PBS processes auction request" + def response = enabledDefaultService.sendAuctionRequest(bidRequest) + + then: "Bidder request contains gzip content encoding" + assert response.ext?.debug?.httpcalls?.get(GENERIC.value)?.requestHeaders?.first() + ?.get(CONTENT_ENCODING_HEADER)?.first() == GZIP.value + } + + def "PBS should omit content encoding when endpoint compression is none"() { + given: "Default bidRequest" + def bidRequest = BidRequest.defaultBidRequest + + when: "PBS processes auction request" + def response = disabledDefaultService.sendAuctionRequest(bidRequest) + + then: "Bidder request has no content encoding" + assert !response.ext?.debug?.httpcalls?.get(GENERIC.value)?.requestHeaders?.first() + ?.get(CONTENT_ENCODING_HEADER) + } + + def "PBS should forward configured server information to bidder"() { + given: "PBS with server info configuration" + def serverDataCenter = PBSUtils.randomString + def serverExternalUrl = "https://${PBSUtils.randomString}.com/".toString() + def serverHostVendorId = PBSUtils.randomNumber + def pbsConfig = [ + "datacenter-region" : serverDataCenter, + "external-url" : serverExternalUrl, + "gdpr.host-vendor-id": serverHostVendorId.toString() + ] + def pbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Bid request" + def bidRequest = BidRequest.defaultBidRequest + + when: "PBS processes auction request" + pbsService.sendAuctionRequest(bidRequest) + + then: "Bidder request contains configured server information" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest?.ext?.prebid?.server?.externalUrl == serverExternalUrl + assert bidderRequest.ext.prebid.server.datacenter == serverDataCenter + assert bidderRequest.ext.prebid.server.gvlId == serverHostVendorId + } +} diff --git a/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderCurrencySpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderCurrencySpec.groovy new file mode 100644 index 00000000000..5d6811f977e --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderCurrencySpec.groovy @@ -0,0 +1,240 @@ +package org.prebid.server.functional.tests.bidder + +import org.prebid.server.functional.model.bidder.BidderName +import org.prebid.server.functional.model.bidder.Generic +import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.model.response.auction.BidResponse +import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.Dependencies +import org.prebid.server.functional.tests.BaseSpec + +import static org.prebid.server.functional.model.Currency.EUR +import static org.prebid.server.functional.model.Currency.GBP +import static org.prebid.server.functional.model.Currency.JPY +import static org.prebid.server.functional.model.Currency.USD +import static org.prebid.server.functional.model.response.auction.BidRejectionReason.REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY +import static org.prebid.server.functional.model.response.auction.ErrorType.ALIAS +import static org.prebid.server.functional.model.response.auction.ErrorType.GENERIC + +class BidderCurrencySpec extends BaseSpec { + + private static final PrebidServerService noCurrencyAcceptedService = pbsServiceFactory.getService( + "adapters.${BidderName.GENERIC}.meta-info.currency-accepted": "", + "adapters.${BidderName.GENERIC}.aliases.${BidderName.ALIAS}.enabled": "true", + "adapters.${BidderName.GENERIC}.aliases.${BidderName.ALIAS}.meta-info.vendor-id": "0", + "adapters.${BidderName.GENERIC}.aliases.${BidderName.ALIAS}.endpoint": "$Dependencies.networkServiceContainer.rootUri/auction".toString(), + "adapters.${BidderName.GENERIC}.aliases.${BidderName.ALIAS}.meta-info.currency-accepted": "" + ) + + private static PrebidServerService withCurrencyAcceptedService = pbsServiceFactory.getService( + "adapters.generic.meta-info.currency-accepted": "${USD},${GBP}".toString(), + "adapters.${BidderName.GENERIC}.aliases.${BidderName.ALIAS}.enabled": "true", + "adapters.${BidderName.GENERIC}.aliases.${BidderName.ALIAS}.meta-info.vendor-id": "0", + "adapters.${BidderName.GENERIC}.aliases.${BidderName.ALIAS}.endpoint": "$Dependencies.networkServiceContainer.rootUri/auction".toString(), + "adapters.${BidderName.GENERIC}.aliases.${BidderName.ALIAS}.meta-info.currency-accepted": "${EUR},${JPY}".toString() + ) + + def "PBS should send request to bidder when adapters.bidder.meta-info.currency-accepted not specified"() { + given: "Default bid request with generic bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + cur = [USD] + ext.prebid.returnAllBidStatus = true + } + + when: "PBS processes auction request" + def response = noCurrencyAcceptedService.sendAuctionRequest(bidRequest) + + then: "Response should contain http calls" + assert response.ext?.debug?.httpcalls[BidderName.GENERIC.value] + + and: "Response should contain seatBid" + assert response.seatbid.bid.flatten().size() == 1 + + and: "Bidder request should be valid" + assert bidder.getBidderRequest(bidRequest.id) + + and: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "Response shouldn't contain warning" + assert !response.ext?.warnings + + and: "PBS response shouldn't contain seatNonBid" + assert !response.ext.seatnonbid + } + + def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted not specified"() { + given: "Default bid request with alias bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + cur = [USD] + ext.prebid.returnAllBidStatus = true + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.generic = null + } + + when: "PBS processes auction request" + def response = noCurrencyAcceptedService.sendAuctionRequest(bidRequest) + + then: "Response should contain http calls" + assert response.ext?.debug?.httpcalls[BidderName.ALIAS.value] + + and: "Response should contain seatBid" + assert response.seatbid.bid.flatten().size() == 1 + + and: "Bidder request should be valid" + assert bidder.getBidderRequest(bidRequest.id) + + and: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "Response shouldn't contain warning" + assert !response.ext?.warnings + + and: "PBS response shouldn't contain seatNonBid" + assert !response.ext.seatnonbid + } + + def "PBS should send request to bidder when adapters.bidder.meta-info.currency-accepted intersect with requested currency"() { + given: "Default basic generic BidRequest" + def bidRequest = BidRequest.defaultBidRequest.tap { + cur = [USD] + ext.prebid.returnAllBidStatus = true + } + + when: "PBS processes auction request" + def response = withCurrencyAcceptedService.sendAuctionRequest(bidRequest) + + then: "Response should contain http calls" + assert response.ext?.debug?.httpcalls[BidderName.GENERIC.value] + + and: "Response should contain seatBid" + assert response.seatbid.bid.flatten().size() == 1 + + and: "Bidder request should be valid" + assert bidder.getBidderRequest(bidRequest.id) + + and: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "Response shouldn't contain warning" + assert !response.ext?.warnings + + and: "PBS response shouldn't contain seatNonBid and contain errors" + assert !response.ext.seatnonbid + } + + def "PBS shouldn't send request to bidder and emit warning when adapters.bidder.meta-info.currency-accepted not intersect with requested currency"() { + given: "Default basic generic BidRequest" + def bidRequest = BidRequest.defaultBidRequest.tap { + cur = [EUR] + ext.prebid.returnAllBidStatus = true + } + + when: "PBS processes auction request" + def response = withCurrencyAcceptedService.sendAuctionRequest(bidRequest) + + then: "Response shouldn't contain http calls" + assert !response.ext?.debug?.httpcalls + + and: "Response shouldn't contain seatBid" + assert !response.seatbid + + and: "Pbs shouldn't make bidder request" + assert !bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "Response should seatNon bid with code 205" + assert response.ext.seatnonbid.size() == 1 + + and: "PBS should emit an warnings" + assert response.ext?.warnings[GENERIC]*.code == [999] + assert response.ext?.warnings[GENERIC]*.message == + ["No match between the configured currencies and bidRequest.cur"] + + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == BidderName.GENERIC + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY + } + + def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted intersect with requested currency"() { + given: "Default basic BidRequest with alias bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + cur = [JPY] + ext.prebid.returnAllBidStatus = true + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.generic = null + } + + and: "Default bid response" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + cur = JPY + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = withCurrencyAcceptedService.sendAuctionRequest(bidRequest) + + then: "Response should contain http calls" + assert response.ext?.debug?.httpcalls[ALIAS.value] + + and: "Response should contain seatBid" + assert response.seatbid.bid.flatten().size() == 1 + + and: "Bidder request should be valid" + assert bidder.getBidderRequest(bidRequest.id) + + and: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "Response shouldn't contain warning" + assert !response.ext?.warnings + + and: "PBS response shouldn't contain seatNonBid and contain errors" + assert !response.ext.seatnonbid + } + + def "PBS shouldn't send request to bidder and emit warning when adapters.bidder.aliases.bidder.meta-info.currency-accepted not intersect with requested currency"() { + given: "Default basic BidRequest with alias bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + cur = [GBP] + ext.prebid.returnAllBidStatus = true + imp[0].ext.prebid.bidder.alias = new Generic() + imp[0].ext.prebid.bidder.generic = null + } + + and: "Default bid response" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest) + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = withCurrencyAcceptedService.sendAuctionRequest(bidRequest) + + then: "Response shouldn't contain http calls" + assert !response.ext?.debug?.httpcalls + + and: "Response shouldn't contain seatBid" + assert !response.seatbid + + and: "Pbs shouldn't make bidder request" + assert !bidder.getBidderRequests(bidRequest.id) + + and: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "PBS should emit an warnings" + assert response.ext?.warnings[ALIAS]*.code == [999] + assert response.ext?.warnings[ALIAS]*.message == + ["No match between the configured currencies and bidRequest.cur"] + + and: "Response should seatNon bid with code 205" + assert response.ext.seatnonbid.size() == 1 + + def seatNonBid = response.ext.seatnonbid[0] + assert seatNonBid.seat == BidderName.ALIAS + assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id + assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY + } +} diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidderFieldDisplayBehaviorSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderFieldDisplayBehaviorSpec.groovy similarity index 99% rename from src/test/groovy/org/prebid/server/functional/tests/BidderFieldDisplayBehaviorSpec.groovy rename to src/test/groovy/org/prebid/server/functional/tests/bidder/BidderFieldDisplayBehaviorSpec.groovy index 57df9ae7c53..1caf9e63d5c 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderFieldDisplayBehaviorSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderFieldDisplayBehaviorSpec.groovy @@ -1,4 +1,4 @@ -package org.prebid.server.functional.tests +package org.prebid.server.functional.tests.bidder import org.prebid.server.functional.model.ChannelType import org.prebid.server.functional.model.bidder.Generic @@ -42,6 +42,7 @@ import org.prebid.server.functional.model.request.auction.UserExt import org.prebid.server.functional.model.request.auction.UserExtPrebid import org.prebid.server.functional.model.request.auction.UserTime import org.prebid.server.functional.model.response.auction.BidResponse +import org.prebid.server.functional.tests.BaseSpec import org.prebid.server.functional.util.PBSUtils import static org.prebid.server.functional.model.Currency.USD diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidderFormatSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderFormatSpec.groovy similarity index 99% rename from src/test/groovy/org/prebid/server/functional/tests/BidderFormatSpec.groovy rename to src/test/groovy/org/prebid/server/functional/tests/bidder/BidderFormatSpec.groovy index b47a2e47ddf..7bf91e84a89 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderFormatSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderFormatSpec.groovy @@ -1,4 +1,4 @@ -package org.prebid.server.functional.tests +package org.prebid.server.functional.tests.bidder import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.config.AccountAuctionConfig @@ -18,6 +18,7 @@ import org.prebid.server.functional.model.request.auction.Video import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.tests.BaseSpec import org.prebid.server.functional.util.PBSUtils import spock.lang.PendingFeature import spock.lang.Shared diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidderInsensitiveCaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderInsensitiveCaseSpec.groovy similarity index 98% rename from src/test/groovy/org/prebid/server/functional/tests/BidderInsensitiveCaseSpec.groovy rename to src/test/groovy/org/prebid/server/functional/tests/bidder/BidderInsensitiveCaseSpec.groovy index ef74c3a9a06..2bd3bcc71e9 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderInsensitiveCaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderInsensitiveCaseSpec.groovy @@ -1,4 +1,4 @@ -package org.prebid.server.functional.tests +package org.prebid.server.functional.tests.bidder import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.db.StoredResponse @@ -16,12 +16,11 @@ import org.prebid.server.functional.model.request.auction.StoredBidResponse import org.prebid.server.functional.model.request.auction.Targeting import org.prebid.server.functional.model.request.auction.Uid import org.prebid.server.functional.model.request.auction.User -import org.prebid.server.functional.model.request.auction.UserExt -import org.prebid.server.functional.model.request.auction.UserExtPrebid import org.prebid.server.functional.model.request.cookiesync.CookieSyncRequest import org.prebid.server.functional.model.response.auction.Bid import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ErrorType +import org.prebid.server.functional.tests.BaseSpec import org.prebid.server.functional.util.PBSUtils import static org.prebid.server.functional.model.bidder.BidderName.ALIAS diff --git a/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderMediaFilteringSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderMediaFilteringSpec.groovy new file mode 100644 index 00000000000..5ae43eb79b7 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderMediaFilteringSpec.groovy @@ -0,0 +1,270 @@ +package org.prebid.server.functional.tests.bidder + +import org.prebid.server.functional.model.bidder.BidderName +import org.prebid.server.functional.model.bidder.Generic +import org.prebid.server.functional.model.request.auction.Banner +import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.model.request.auction.DistributionChannel +import org.prebid.server.functional.model.request.auction.Imp +import org.prebid.server.functional.model.request.auction.Native +import org.prebid.server.functional.model.request.auction.Site +import org.prebid.server.functional.model.response.auction.Adm +import org.prebid.server.functional.model.response.auction.Bid +import org.prebid.server.functional.model.response.auction.BidResponse +import org.prebid.server.functional.model.response.auction.ErrorType +import org.prebid.server.functional.tests.BaseSpec +import org.prebid.server.functional.util.PBSUtils + +import static org.prebid.server.functional.model.bidder.BidderName.ALIAS +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC +import static org.prebid.server.functional.model.bidder.BidderName.GENER_X +import static org.prebid.server.functional.model.request.auction.Asset.getTitleAsset +import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP +import static org.prebid.server.functional.model.request.auction.DistributionChannel.DOOH +import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE +import static org.prebid.server.functional.model.response.auction.MediaType.AUDIO +import static org.prebid.server.functional.model.response.auction.MediaType.BANNER +import static org.prebid.server.functional.model.response.auction.MediaType.NATIVE +import static org.prebid.server.functional.model.response.auction.MediaType.VIDEO + +class BidderMediaFilteringSpec extends BaseSpec { + + private static final Map BIDDER_CONFIG = [ + "adapters.${GENERIC.value}.enabled" : "true", + "adapters.${GENERIC.value}.meta-info.vendor-id" : "0", + "adapters.${GENERIC.value}.meta-info.site-media-types" : "banner,video,native", + "adapters.${GENERIC.value}.meta-info.app-media-types" : "banner,video,native", + "adapters.${GENERIC.value}.meta-info.dooh-media-types" : "banner,video,native,audio", + + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.enabled" : "true", + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.meta-info.vendor-id" : "0", + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.meta-info.site-media-types" : "native,video", + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.meta-info.app-media-types" : "video,native", + "adapters.${GENERIC.value}.aliases.${ALIAS.value}.meta-info.dooh-media-types" : "banner,video,audio", + + "adapters.${GENERIC.value}.aliases.${GENER_X.value}.enabled" : "true", + "adapters.${GENERIC.value}.aliases.${GENER_X.value}.meta-info.vendor-id" : '0', + "adapters.${GENERIC.value}.aliases.${GENER_X.value}.meta-info.site-media-types": "", + "adapters.${GENERIC.value}.aliases.${GENER_X.value}.meta-info.app-media-types" : "", + "adapters.${GENERIC.value}.aliases.${GENER_X.value}.meta-info.dooh-media-types": "", + ] + + private static final filterMediaService = pbsServiceFactory.getService( + BIDDER_CONFIG + ['auction.filter-imp-media-type.enabled': 'true'] + ) + + private static final freeMediaService = pbsServiceFactory.getService( + BIDDER_CONFIG + ['auction.filter-imp-media-type.enabled': 'false'] + ) + + def "PBS should reject #channel request when bidder supports no media types"() { + given: "Bid request for bidder without supported media types" + def bidRequest = getBidderRequest(channel, GENER_X) + + when: "PBS processes auction request" + def response = filterMediaService.sendAuctionRequest(bidRequest) + + then: "Response should contain no bids" + assert response.seatbid.isEmpty() + + and: "Response should warn about unsupported media types" + assert response.ext?.warnings[ErrorType.GENER_X]*.code == [2] + assert response.ext?.warnings[ErrorType.GENER_X]*.message == ["Bidder does not support any media types."] + + where: + channel << [SITE, APP, DOOH] + } + + def "PBS should accept #channel request when bidder supports no media types and filtering is disabled"() { + given: "Bid request for bidder without supported media types" + def bidRequest = getBidderRequest(channel, GENER_X) + + when: "PBS processes auction request" + def response = freeMediaService.sendAuctionRequest(bidRequest) + + then: "Response should contain bids" + assert response.seatbid + + and: "Response should contain no errors" + assert !response.ext?.errors + + where: + channel << [SITE, APP, DOOH] + } + + def "PBS should remove unsupported banner and retain native media type in SITE impression"() { + given: "SITE request with banner and native media types" + def bidRequest = getBidderRequest(SITE, ALIAS).tap { + site = Site.defaultSite + imp[0].banner = Banner.defaultBanner + imp[0].nativeObj = Native.defaultNative + } + + and: "Bidder response for the impression" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest) + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = filterMediaService.sendAuctionRequest(bidRequest) + + then: "Bidder should receive native media type without banner" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert !bidderRequest.imp[0]?.banner + assert bidderRequest.imp[0]?.nativeObj + + and: "Response should contain no warnings" + assert !response.ext?.warnings + } + + def "PBS should retain unsupported banner in SITE impression when filtering is disabled"() { + given: "SITE request with banner and native media types" + def bidRequest = getBidderRequest(SITE, ALIAS).tap { + site = Site.defaultSite + imp[0].banner = Banner.defaultBanner + imp[0].nativeObj = Native.defaultNative + } + + when: "PBS processes auction request" + def response = freeMediaService.sendAuctionRequest(bidRequest) + + then: "Bidder should receive both media types" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0]?.banner + assert bidderRequest.imp[0]?.nativeObj + + and: "Response should contain no errors" + assert !response.ext?.errors + } + + def "PBS should remove unsupported banner impression and retain native impression in SITE request"() { + given: "SITE request with banner and native impressions" + def nativeImp = Imp.getDefaultImpression(NATIVE).tap { + ext.prebid.bidder.generic = null + ext.prebid.bidder.alias = new Generic() + } + def bidRequest = getBidderRequest(SITE, ALIAS).tap { + site = Site.defaultSite + imp << nativeImp + } + + and: "Bidder response for supported native impression" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid.first().bid = [Bid.getDefaultBid(nativeImp)] + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = filterMediaService.sendAuctionRequest(bidRequest) + + then: "Bidder should receive only the native impression" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp.id == [nativeImp.id] + assert bidderRequest.imp.first().nativeObj + + and: "Response should warn about the removed banner impression" + assert response.ext?.warnings[ErrorType.ALIAS]*.code == [2] + assert response.ext?.warnings[ErrorType.ALIAS]*.message == + ["Imp ${bidRequest.imp[0].id} does not have a supported media type and has been removed from the " + + "request for this bidder." as String] + + and: "Response should contain bids" + assert response.seatbid + } + + def "PBS should reject SITE request when all impressions have unsupported media types"() { + given: "SITE request with unsupported banner impression" + def bidRequest = getBidderRequest(SITE, ALIAS).tap { + site = Site.defaultSite + imp.first().banner = Banner.defaultBanner + } + + when: "PBS processes auction request" + def response = filterMediaService.sendAuctionRequest(bidRequest) + + then: "Bidder should not receive a request" + assert bidder.getRequestCount(bidRequest.id) == 0 + + and: "Response should warn about the removed impression and empty request" + assert response.ext?.warnings[ErrorType.ALIAS]*.code == [2, 2] + assert response.ext?.warnings[ErrorType.ALIAS]*.message == + ["Imp ${bidRequest.imp[0].id} does not have a supported media type and has been removed from the request for this bidder." as String, + "Bid request contains 0 impressions after filtering."] + + and: "Response should contain no bids" + assert response.seatbid.isEmpty() + } + + def "PBS should reject DOOH request when all impressions have unsupported media types"() { + given: "DOOH request with unsupported native impression" + def bidRequest = getBidderRequest(DOOH, ALIAS).tap { + imp.first().banner = null + imp.first().nativeObj = Native.defaultNative + } + + when: "PBS processes auction request" + def response = filterMediaService.sendAuctionRequest(bidRequest) + + then: "Bidder should not receive a request" + assert !bidder.getBidderRequests(bidRequest.id) + + and: "Response should warn about the removed impression and empty request" + assert response.ext?.warnings[ErrorType.ALIAS]*.code == [2, 2] + assert response.ext?.warnings[ErrorType.ALIAS]*.message == + ["Imp ${bidRequest.imp[0].id} does not have a supported media type and has been removed from the request for this bidder." as String, + "Bid request contains 0 impressions after filtering."] + + and: "Response should contain no bids" + assert !response.seatbid + } + + def "PBS should retain #mediaType impression and remove unsupported native impression in DOOH request"() { + given: "DOOH request with supported and unsupported impressions" + def bidRequest = getBidderRequest(DOOH, ALIAS).tap { + imp = [Imp.getDefaultImpression(mediaType), Imp.getDefaultImpression(NATIVE)] + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.alias = new Generic() + imp[1].ext.prebid.bidder.generic = null + imp[1].ext.prebid.bidder.alias = new Generic() + } + + and: "Bidder response for supported impression" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].adm = new Adm(assets: [titleAsset]) + seatbid[0].bid[0].nurl = PBSUtils.randomString + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = filterMediaService.sendAuctionRequest(bidRequest) + + then: "Bidder should receive only the supported impression" + assert bidder.getBidderRequest(bidRequest.id).imp.id == [bidRequest.imp.first().id] + + and: "Response should warn about the removed native impression" + assert response.ext?.warnings[ErrorType.ALIAS]*.code == [2] + assert response.ext?.warnings[ErrorType.ALIAS]*.message == + ["Imp ${bidRequest.imp[1].id} does not have a supported media type and has been removed from the request for this bidder." as String] + + and: "Response should contain bids" + assert response.seatbid + + where: + mediaType << [BANNER, VIDEO, AUDIO] + } + + private static BidRequest getBidderRequest(DistributionChannel channel, BidderName bidder) { + return BidRequest.getDefaultBidRequest(channel).tap { + if (bidder != GENERIC) { + imp.first().ext.prebid.bidder.with { + generic = null + + if (bidder == GENER_X) { + generX = new Generic() + } else if (bidder == ALIAS) { + alias = new Generic() + } + } + } + } + } +} diff --git a/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderParamsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderParamsSpec.groovy new file mode 100644 index 00000000000..905e75dffd1 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/bidder/BidderParamsSpec.groovy @@ -0,0 +1,568 @@ +package org.prebid.server.functional.tests.bidder + +import org.prebid.server.functional.model.bidder.AppNexus +import org.prebid.server.functional.model.bidder.BidderName +import org.prebid.server.functional.model.bidder.Generic +import org.prebid.server.functional.model.db.StoredImp +import org.prebid.server.functional.model.db.StoredRequest +import org.prebid.server.functional.model.request.amp.AmpRequest +import org.prebid.server.functional.model.request.auction.Adrino +import org.prebid.server.functional.model.request.auction.AnyUnsupportedBidder +import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.model.request.auction.Imp +import org.prebid.server.functional.model.request.auction.ImpExt +import org.prebid.server.functional.model.request.auction.ImpExtContext +import org.prebid.server.functional.model.request.auction.ImpExtContextData +import org.prebid.server.functional.model.request.auction.PrebidOptions +import org.prebid.server.functional.model.request.auction.PrebidStoredRequest +import org.prebid.server.functional.model.request.auction.Source +import org.prebid.server.functional.model.request.auction.Targeting +import org.prebid.server.functional.model.response.auction.BidExt +import org.prebid.server.functional.model.response.auction.BidResponse +import org.prebid.server.functional.testcontainers.Dependencies +import org.prebid.server.functional.tests.BaseSpec +import org.prebid.server.functional.util.PBSUtils + +import static org.prebid.server.functional.model.Currency.USD +import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC_CAMEL_CASE +import static org.prebid.server.functional.model.bidder.BidderName.OPENX +import static org.prebid.server.functional.model.request.auction.SecurityLevel.NON_SECURE +import static org.prebid.server.functional.model.request.auction.SecurityLevel.SECURE +import static org.prebid.server.functional.model.response.auction.ErrorType.GENERIC +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID + +class BidderParamsSpec extends BaseSpec { + + def "PBS should prefer bidder params from imp[*].ext.prebid.bidder.BIDDER when ext.prebid.bidderparams.BIDDER is specified"() { + given: "Default basic BidRequest" + def bidRequest = BidRequest.defaultBidRequest + def firstParam = PBSUtils.randomNumber + bidRequest.imp.first().ext.prebid.bidder.generic = new Generic(firstParam: firstParam) + + and: "Set bidderParam to bidRequest" + bidRequest.ext.prebid.bidderParams = [(BidderName.GENERIC): [firstParam: PBSUtils.randomNumber]] + + when: "PBS processes auction request" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain firstParam value from imp[*].ext.prebid.bidder.BIDDER" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0]?.ext?.bidder?.firstParam == firstParam + + and: "Bidder request should contain requested bidder param for related itself bidder" + assert bidderRequest.ext.prebid.bidderParams[GENERIC] == bidRequest.ext.prebid.bidderParams[GENERIC] + } + + def "PBS should send bidder params from imp[*].ext.prebid.bidder.BIDDER when ext.prebid.bidderparams.BIDDER isn't specified"() { + given: "Default basic BidRequest" + def bidRequest = BidRequest.defaultBidRequest + def firstParam = PBSUtils.randomNumber + bidRequest.imp.first().ext.prebid.bidder.generic = new Generic(firstParam: firstParam) + + and: "Set bidderParam = null to bidRequest" + bidRequest.ext.prebid.bidderParams = null + + when: "PBS processes auction request" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain firstParam value from imp[*].ext.prebid.bidder.BIDDER" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0]?.ext?.bidder?.firstParam == firstParam + } + + def "PBS should merge bidder params from imp[*].ext.prebid.bidder.BIDDER and ext.prebid.bidderparams.BIDDER"() { + given: "Default basic BidRequest" + def bidRequest = BidRequest.defaultBidRequest + def firstParam = PBSUtils.randomNumber + bidRequest.imp.first().ext.prebid.bidder.generic = new Generic(firstParam: firstParam) + + and: "Set bidderParam to bidRequest" + def secondParam = PBSUtils.randomNumber + bidRequest.ext.prebid.bidderParams = [(BidderName.GENERIC): [secondParam: secondParam]] + + when: "PBS processes auction request" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should merge bidder params" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0]?.ext?.bidder?.firstParam == firstParam + assert bidderRequest.imp[0]?.ext?.bidder?.secondParam == secondParam + } + + def "PBS should only send bidder params from ext.prebid.bidderparams.BIDDER to specified bidder"() { + given: "Default basic BidRequest" + def bidRequest = BidRequest.defaultBidRequest + def firstParam = PBSUtils.randomNumber + bidRequest.imp.first().ext.prebid.bidder.generic = new Generic(firstParam: firstParam) + bidRequest.imp.first().ext.prebid.bidder.appNexus = null + + and: "Set bidderParam to bidRequest" + bidRequest.ext.prebid.bidderParams = [(APPNEXUS): [placement_id: PBSUtils.randomNumber]] + + when: "PBS processes auction request" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder request should not contain params from another bidder" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0].ext.bidder.firstParam == firstParam + assert !bidderRequest.imp[0].ext.bidder.placementId + } + + def "PBS should reject bidder when bidder params from request doesn't satisfy json-schema for auction request"() { + given: "BidRequest with bad bidder datatype" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp << Imp.defaultImpression + imp[0].ext.prebid.bidder.generic.exampleProperty = PBSUtils.randomNumber + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "PBS should not fail the entire auction" + assert response.seatbid[0].bid.size() == 1 + + and: "Bidder request should contain only valid impression" + assert bidder.getBidderRequest(bidRequest.id).imp*.id == [bidRequest.imp[1].id] + + and: "Bidder with invalid params should be dropped" + assert response.ext?.warnings[PREBID]*.code == [999, 999] + assert response.ext?.warnings[PREBID]*.message == + ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + + "\$.exampleProperty: integer found, string expected", + "WARNING: request.imp[0].ext must contain at least one valid bidder"] + } + + def "PBS should reject bidder when bidder params from stored request doesn't satisfy json-schema for auction request"() { + given: "BidRequest with stored request, without imp" + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomNumber) + imp = null + } + + and: "Default stored request with bad bidder datatype" + def storedRequestModel = BidRequest.defaultStoredRequest.tap { + imp[0].ext.prebid.bidder.generic.exampleProperty = PBSUtils.randomNumber + } + + and: "Save storedRequest into DB" + def storedRequest = StoredRequest.getStoredRequest(bidRequest, storedRequestModel) + storedRequestDao.save(storedRequest) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder should be dropped" + assert response.ext?.warnings[PREBID]*.code == [999, 999] + assert response.ext?.warnings[PREBID]*.message == + ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + + "\$.exampleProperty: integer found, string expected", + "WARNING: request.imp[0].ext must contain at least one valid bidder"] + + and: "PBS should not call bidder" + assert bidder.getRequestCount(bidRequest.id) == 0 + + and: "seatbid should be empty" + assert response.seatbid.isEmpty() + } + + def "PBS should reject bidder when bidder params from stored request doesn't satisfy json-schema for amp request"() { + given: "AmpRequest with bad bidder datatype" + def ampRequest = AmpRequest.defaultAmpRequest + def ampStoredRequest = BidRequest.defaultBidRequest.tap { + site.publisher.id = ampRequest.account + imp[0].ext.prebid.bidder.generic.exampleProperty = PBSUtils.randomNumber + } + + and: "Save storedRequest into DB" + def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest) + storedRequestDao.save(storedRequest) + + when: "PBS processes amp request" + def response = defaultPbsService.sendAmpRequest(ampRequest) + + then: "Bidder should be dropped" + assert response.ext?.warnings[PREBID]*.code == [999, 999] + assert response.ext?.warnings[PREBID]*.message == + ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + + "\$.exampleProperty: integer found, string expected", + "WARNING: request.imp[0].ext must contain at least one valid bidder"] + + and: "PBS should not call bidder" + assert bidder.getRequestCount(ampStoredRequest.id) == 0 + + and: "targeting should be empty" + assert response.targeting.isEmpty() + } + + def "PBS should not treat reserved imp[].ext.tid as bidder"() { + given: "Default basic BidRequest with imp[].ext.tid object" + def bidRequest = BidRequest.defaultBidRequest + def tid = PBSUtils.getRandomString() + bidRequest.imp.first().ext.tid = tid + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "imp[].ext.tid object should be passed to a bidder" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp?.first()?.ext?.tid == tid + + and: "Response shouldn't contain warning" + assert !response.ext?.warnings + } + + def "PBS auction should populate imp[0].secure depend which value in imp stored request"() { + given: "Default bid request" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomString) + } + + and: "Save storedImp into DB" + def storedImp = StoredImp.getStoredImp(bidRequest).tap { + impData = Imp.defaultImpression.tap { + it.secure = secureStoredRequest + } + } + storedImpDao.save(storedImp) + + when: "Requesting PBS auction" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain imp[0].secure same value as in request" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0].secure == secureBidderRequest + + where: + secureStoredRequest | secureBidderRequest + null | SECURE + SECURE | SECURE + NON_SECURE | NON_SECURE + } + + def "PBS auction should populate imp[0].secure depend which value in imp request"() { + given: "Default bid request" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].secure = secureRequest + } + + when: "Requesting PBS auction" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain imp[0].secure same value as in request" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0].secure == secureBidderRequest + + where: + secureRequest | secureBidderRequest + null | SECURE + SECURE | SECURE + NON_SECURE | NON_SECURE + } + + def "PBS shouldn't emit warning and proceed auction when imp.ext.anyUnsupportedBidder and imp.ext.prebid.bidder.generic in the request"() { + given: "Default bid request" + def unsupportedBidder = new AnyUnsupportedBidder(anyUnsupportedField: PBSUtils.randomString) + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.anyUnsupportedBidder = unsupportedBidder + imp[0].ext.prebid.bidder.generic = new Generic() + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain imp.ext.anyUnsupportedBidder" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0].ext.anyUnsupportedBidder == unsupportedBidder + + and: "Response shouldn't contain warning" + assert !response?.ext?.warnings + } + + def "PBS should emit warning and proceed auction when imp.ext.anyUnsupportedBidder and imp.ext.generic in the request"() { + given: "Default bid request" + def unsupportedBidder = new AnyUnsupportedBidder(anyUnsupportedField: PBSUtils.randomString) + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.generic = new Generic() + imp[0].ext.anyUnsupportedBidder = unsupportedBidder + imp[0].ext.prebid.bidder = null + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain imp.ext.anyUnsupportedBidder" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0].ext.anyUnsupportedBidder == unsupportedBidder + + and: "PBS should emit an warning" + assert response?.ext?.warnings[PREBID]*.code == [999] + assert response?.ext?.warnings[PREBID]*.message == + ["WARNING: request.imp[0].ext.prebid.bidder.anyUnsupportedBidder was dropped with a reason: " + + "request.imp[0].ext.prebid.bidder contains unknown bidder: anyUnsupportedBidder"] + } + + def "PBS should emit warning and proceed auction when ext.prebid fields include adunitcode"() { + given: "Default bid request with populated ext.prebid.bidderParams" + def genericBidderParams = PBSUtils.randomString + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.bidderParams = [adUnitCode : PBSUtils.randomString, + (GENERIC.value): genericBidderParams] + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "PBS should emit an warning" + assert response?.ext?.warnings[PREBID]*.code == [999] + assert response?.ext?.warnings[PREBID]*.message == + ["WARNING: request.imp[0].ext.prebid.bidder.adUnitCode was dropped with a reason: " + + "request.imp[0].ext.prebid.bidder contains unknown bidder: adUnitCode"] + } + + def "PBS shouldn't emit warning and proceed auction when all imp.ext fields known for PBS"() { + given: "Default bid request with populated imp.ext" + def impExt = ImpExt.getDefaultImpExt().tap { + prebid.bidder.generic = null + prebid.adUnitCode = PBSUtils.randomString + generic = new Generic() + all = PBSUtils.randomNumber + context = new ImpExtContext(data: new ImpExtContextData()) + data = new ImpExtContextData(pbAdSlot: PBSUtils.randomString) + general = PBSUtils.randomString + gpid = PBSUtils.randomString + skadn = PBSUtils.randomString + tid = PBSUtils.randomString + } + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext = impExt + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "Response shouldn't contain warning" + assert !response.ext?.warnings + + and: "Bidder request should contain same field as requested" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + verifyAll(bidderRequest.imp[0].ext) { + it.bidder == impExt.generic + it.all == impExt.all + it.context == impExt.context + it.data == impExt.data + it.general == impExt.general + it.gpid == impExt.gpid + it.skadn == impExt.skadn + it.tid == impExt.tid + it.prebid.adUnitCode == impExt.prebid.adUnitCode + } + } + + def "PBS shouldn't emit warning and proceed auction when all imp.ext.prebid fields known for PBS"() { + given: "PBS with old ortb version" + def pbsConfig = ['adapters.generic.ortb-version': '2.5'] + def pbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Default bid request with populated imp.ext.prebid" + def impExt = ImpExt.getDefaultImpExt().tap { + prebid.adUnitCode = PBSUtils.randomString + prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomString) + prebid.isRewardedInventory = PBSUtils.getRandomNumber(0, 1) + prebid.options = new PrebidOptions(echoVideoAttrs: PBSUtils.randomBoolean) + } + def bidRequest = BidRequest.defaultVideoRequest.tap { + imp[0].rwdd = null + imp[0].ext = impExt + } + + and: "Save storedImp into DB" + def storedImp = StoredImp.getStoredImp(bidRequest) + storedImpDao.save(storedImp) + + and: "Default bid response" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest) + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "Response shouldn't contain warning" + assert !response.ext?.warnings + + and: "Bidder request should contain same field as requested" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + verifyAll(bidderRequest.imp[0].ext.prebid) { + it.adUnitCode == impExt.prebid.adUnitCode + it.storedRequest == impExt.prebid.storedRequest + it.isRewardedInventory == impExt.prebid.isRewardedInventory + it.options.echoVideoAttrs == impExt.prebid.options.echoVideoAttrs + } + } + + def "PBS should proceed auction without warning when all ext.prebid.bidderParams fields are known"() { + given: "Default bid request with populated ext.prebid.bidderParams" + def genericBidderParams = PBSUtils.randomString + def bidRequest = BidRequest.defaultBidRequest.tap { + ext.prebid.bidderParams = [all : PBSUtils.randomString, + context : PBSUtils.randomString, + data : PBSUtils.randomString, + general : PBSUtils.randomString, + gpid : PBSUtils.randomString, + skadn : PBSUtils.randomString, + tid : PBSUtils.randomString, + (GENERIC.value): genericBidderParams + ] + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response shouldn't contain error" + assert !response.ext?.errors + + and: "Response shouldn't contain warning" + assert !response.ext?.warnings + + and: "Bidder request should bidderParams only for bidder" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.ext.prebid.bidderParams == [(GENERIC.value): genericBidderParams] + } + + def "PBS should reject alias bidders when bidder params from request doesn't satisfy own json-schema"() { + given: "Default bid request" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.tap { + it.generic.exampleProperty = PBSUtils.randomNumber + //Adrino hard coded bidder alias in generic.yaml + it.adrino = new Adrino(hash: PBSUtils.randomNumber) + } + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder should be dropped" + assert response.ext?.warnings[PREBID]*.code == [999, 999, 999] + assert response.ext?.warnings[PREBID]*.message == + ["WARNING: request.imp[0].ext.prebid.bidder.generic was dropped with a reason: " + + "request.imp[0].ext.prebid.bidder.generic failed validation.\n" + + "\$.exampleProperty: integer found, string expected", + "WARNING: request.imp[0].ext.prebid.bidder.adrino was dropped with a reason: " + + "request.imp[0].ext.prebid.bidder.adrino failed validation.\n" + + "\$.hash: integer found, string expected", + "WARNING: request.imp[0].ext must contain at least one valid bidder"] + + and: "PBS should not call bidder" + assert bidder.getRequestCount(bidRequest.id) == 0 + + and: "targeting should be empty" + assert response.seatbid.isEmpty() + } + + def "PBS should send bidder code from imp[].ext.prebid.bidder to seatbid.bid.ext.prebid.meta.adapterCode"() { + given: "Default basic bid request" + def bidRequest = BidRequest.defaultBidRequest + + and: "Default bid response" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].seat = OPENX + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + + and: "Bidder request should be valid" + assert bidder.getBidderRequest(bidRequest.id) + } + + def "PBS should populate targeting with bidder in camel case when bidder with camel case was requested"() { + given: "Default bid request" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.genericCamelCase = new Generic() + it.ext.prebid.targeting = new Targeting() + } + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Response should contain bidder targeting" + def targeting = response.seatbid[0].bid[0].ext.prebid.targeting + assert targeting["hb_pb_${GENERIC_CAMEL_CASE}"] + assert targeting["hb_size_${GENERIC_CAMEL_CASE}"] + assert targeting["hb_bidder"] == GENERIC_CAMEL_CASE.value + assert targeting["hb_bidder_${GENERIC_CAMEL_CASE}"] == GENERIC_CAMEL_CASE.value + + and: "Bid response should contain seat" + assert response.seatbid.seat == [GENERIC_CAMEL_CASE] + + and: "Response should contain repose millis with corresponding bidder" + assert response.ext.responsetimemillis.containsKey(GENERIC_CAMEL_CASE.value) + + and: "Response should contain adapter code" + assert response.seatbid.bid.ext.prebid.meta.adapterCode.flatten() == [BidderName.GENERIC] + } + + def "PBS should merge stored imp with appnexus bidder requested when reserve field specified"() { + given: "Pbs default config with appnexus" + def pbsConfig = ["adapters.${APPNEXUS.value}.enabled" : "true", + "adapters.${APPNEXUS.value}.endpoint": "$Dependencies.networkServiceContainer.rootUri/auction".toString()] + def defaultPbsService = pbsServiceFactory.getService(pbsConfig) + + and: "Default stored request with specified stored imps and request" + def storedRequestId = PBSUtils.randomString + def bidRequest = BidRequest.getDefaultBidRequest().tap { + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.appNexus = AppNexus.getDefault().tap { + reserve = PBSUtils.getRandomDecimal() as Double + } + imp[0].ext.prebid.storedRequest = new PrebidStoredRequest(id: PBSUtils.randomString) + ext.prebid.storedRequest = new PrebidStoredRequest(id: storedRequestId) + } + + and: "Save storedImp into DB" + def storedImp = StoredImp.getStoredImp(bidRequest).tap { + impData = Imp.defaultImpression + } + storedImpDao.save(storedImp) + + and: "Save stored request with source.tid and cur" + def storedBidRequest = new BidRequest(cur: [USD], source: new Source(tid: PBSUtils.randomString)) + def storedRequest = StoredRequest.getStoredRequest(storedRequestId, storedBidRequest) + storedRequestDao.save(storedRequest) + + and: "Default basic bid with bid.ext" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest, APPNEXUS).tap { + seatbid[0].bid[0].ext = new BidExt() + } + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bid response should contain appnexus and generic bidder" + assert response.seatbid.size() == 2 + assert response.seatbid.seat.sort() == [APPNEXUS, BidderName.GENERIC].sort() + + and: "Bidder requests should perform two bidder call" + def bidderRequests = bidder.getBidderRequests(bidRequest.id) + assert bidderRequests.size() == 2 + } +} diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/AbTestingModuleSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/AbTestingModuleSpec.groovy index de9d940de43..31e236c8d9a 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/AbTestingModuleSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/AbTestingModuleSpec.groovy @@ -8,14 +8,17 @@ import org.prebid.server.functional.model.config.ModuleName import org.prebid.server.functional.model.config.Stage import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest -import org.prebid.server.functional.model.request.auction.FetchStatus +import org.prebid.server.functional.model.request.auction.AnalyticTagStatus import org.prebid.server.functional.model.request.auction.TraceLevel import org.prebid.server.functional.model.response.auction.AnalyticResult import org.prebid.server.functional.model.response.auction.InvocationResult +import org.prebid.server.functional.model.response.auction.ModuleActivityName import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.util.PBSUtils import static org.prebid.server.functional.model.config.HookHttpEndpoint.AUCTION +import static org.prebid.server.functional.model.config.ModuleName.PB_ORTB2_BLOCKING import static org.prebid.server.functional.model.config.ModuleName.PB_RESPONSE_CORRECTION import static org.prebid.server.functional.model.config.Stage.ALL_PROCESSED_BID_RESPONSES import static org.prebid.server.functional.model.config.Stage.BIDDER_REQUEST @@ -24,7 +27,6 @@ import static org.prebid.server.functional.model.request.auction.BidRequest.getD import static org.prebid.server.functional.model.response.auction.InvocationStatus.INVOCATION_FAILURE import static org.prebid.server.functional.model.response.auction.InvocationStatus.SUCCESS import static org.prebid.server.functional.model.response.auction.ModuleActivityName.AB_TESTING -import static org.prebid.server.functional.model.response.auction.ModuleActivityName.ORTB2_BLOCKING import static org.prebid.server.functional.model.response.auction.ResponseAction.NO_ACTION import static org.prebid.server.functional.model.response.auction.ResponseAction.NO_INVOCATION @@ -34,20 +36,20 @@ class AbTestingModuleSpec extends ModuleBaseSpec { private final static Integer MAX_PERCENT_AB = 100 private final static String INVALID_HOOK_MESSAGE = "Hook implementation does not exist or disabled" - private final static Map> ORTB_STAGES = [(BIDDER_REQUEST) : [ModuleName.PB_ORTB2_BLOCKING], - (RAW_BIDDER_RESPONSE): [ModuleName.PB_ORTB2_BLOCKING]] + private final static Map> ORTB_STAGES = [(BIDDER_REQUEST) : [PB_ORTB2_BLOCKING], + (RAW_BIDDER_RESPONSE): [PB_ORTB2_BLOCKING]] private final static Map> RESPONSE_STAGES = [(ALL_PROCESSED_BID_RESPONSES): [PB_RESPONSE_CORRECTION]] private final static Map> MODULES_STAGES = ORTB_STAGES + RESPONSE_STAGES + private final static PbsContainerConfig PB_ORTB2_CONFIG = getModuleBaseSettings(PB_ORTB2_BLOCKING) - private final static Map MULTI_MODULE_CONFIG = getResponseCorrectionConfig() + getOrtb2BlockingSettings() + + private final static PbsContainerConfig MULTI_MODULE_CONFIG = getModuleBaseSettings(PB_RESPONSE_CORRECTION) + + getModuleBaseSettings(PB_ORTB2_BLOCKING) + ['hooks.host-execution-plan': null] - private static final PrebidServerService ortbModulePbsService = pbsServiceFactory.getService(getOrtb2BlockingSettings()) - private static final PrebidServerService pbsServiceWithMultipleModules = pbsServiceFactory.getService(MULTI_MODULE_CONFIG) + private static final PrebidServerService ortbModulePbsService = pbsServiceFactory.getService(PB_ORTB2_CONFIG) def cleanupSpec() { - pbsServiceFactory.removeContainer(getOrtb2BlockingSettings()) - pbsServiceFactory.removeContainer(MULTI_MODULE_CONFIG) + pbsServiceFactory.removeContainer(PB_ORTB2_CONFIG) } def "PBS shouldn't apply a/b test config when config of ab test is disabled"() { @@ -58,7 +60,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { flushMetrics(ortbModulePbsService) and: "Save account with ab test config" - def abTest = AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + def abTest = AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { enabled = false } def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { @@ -83,18 +85,18 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be as default call" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] } def "PBS shouldn't apply valid a/b test config when module is disabled"() { given: "PBS service with disabled module config" - def pbsConfig = getOrtb2BlockingSettings(false) + def pbsConfig = getModuleBaseSettings(PB_ORTB2_BLOCKING, false) def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Default bid request with verbose trace" @@ -105,7 +107,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code)] + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code)] } def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(executionPlan: executionPlan)) def account = new Account(uuid: bidRequest.getAccountId(), config: accountConfig) @@ -125,18 +127,15 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be with error call" def metrics = prebidServerService.sendCollectedMetricsRequest() - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert metrics[EXECUTION_ERROR_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[EXECUTION_ERROR_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[EXECUTION_ERROR_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[EXECUTION_ERROR_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] } def "PBS shouldn't apply a/b test config when module name is not matched"() { @@ -169,16 +168,16 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be as default call" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] where: - moduleName << [ModuleName.PB_ORTB2_BLOCKING.code.toUpperCase(), PBSUtils.randomString] + moduleName << [PB_ORTB2_BLOCKING.code.toUpperCase(), PBSUtils.randomString] } def "PBS should apply a/b test config for each module when multiple config are presents and set to allow modules"() { @@ -189,7 +188,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { flushMetrics(pbsServiceWithMultipleModules) and: "Save account with ab test config" - def ortb2AbTestConfig = AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + def ortb2AbTestConfig = AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { it.percentActive = MAX_PERCENT_AB } def richMediaAbTestConfig = AbTest.getDefault(PB_RESPONSE_CORRECTION.code).tap { @@ -207,14 +206,14 @@ class AbTestingModuleSpec extends ModuleBaseSpec { then: "PBS should apply ab test config for specified module" def invocationResults = response?.ext?.prebid?.modules?.trace?.stages?.outcomes?.groups?.invocationResults?.flatten() as List - def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, ModuleName.PB_ORTB2_BLOCKING) + def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, PB_ORTB2_BLOCKING) verifyAll(ortbBlockingInvocationResults) { it.status == [SUCCESS, SUCCESS] it.action == [NO_ACTION, NO_ACTION] - it.analyticsTags.activities.name.flatten().sort() == [ORTB2_BLOCKING, AB_TESTING, AB_TESTING].value.sort() - it.analyticsTags.activities.status.flatten().sort() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS, FetchStatus.SUCCESS].sort() - it.analyticsTags.activities.results.status.flatten().sort() == [FetchStatus.SUCCESS_ALLOW, FetchStatus.RUN, FetchStatus.RUN].sort() - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.name.flatten().sort() == [ModuleActivityName.PB_ORTB2_BLOCKING, AB_TESTING, AB_TESTING].value.sort() + it.analyticsTags.activities.status.flatten().sort() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS].sort() + it.analyticsTags.activities.results.status.flatten().sort() == [AnalyticTagStatus.SUCCESS_ALLOW, AnalyticTagStatus.RUN, AnalyticTagStatus.RUN].sort() + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "PBS should not apply ab test config for other module" @@ -223,15 +222,15 @@ class AbTestingModuleSpec extends ModuleBaseSpec { it.status == [SUCCESS] it.action == [NO_ACTION] it.analyticsTags.activities.name.flatten() == [AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.RUN] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.RUN] it.analyticsTags.activities.results.values.module.flatten() == [PB_RESPONSE_CORRECTION] } and: "Metric for allowed to run pb-ortb2blocking module should be updated based on ab test config" def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] @@ -250,7 +249,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { flushMetrics(pbsServiceWithMultipleModules) and: "Save account with ab test config" - def ortb2AbTestConfig = AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + def ortb2AbTestConfig = AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { it.percentActive = MIN_PERCENT_AB } def richMediaAbTestConfig = AbTest.getDefault(PB_RESPONSE_CORRECTION.code).tap { @@ -268,14 +267,14 @@ class AbTestingModuleSpec extends ModuleBaseSpec { then: "PBS should apply ab test config for ortb2blocking module" def invocationResults = response?.ext?.prebid?.modules?.trace?.stages?.outcomes?.groups?.invocationResults?.flatten() as List - def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, ModuleName.PB_ORTB2_BLOCKING) + def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, PB_ORTB2_BLOCKING) verifyAll(ortbBlockingInvocationResults) { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "PBS should apply ab test config for pb-response-correction module" @@ -284,15 +283,15 @@ class AbTestingModuleSpec extends ModuleBaseSpec { it.status == [SUCCESS] it.action == [NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED] it.analyticsTags.activities.results.values.module.flatten() == [PB_RESPONSE_CORRECTION] } and: "Metric for skipped pb-ortb2blocking module should be updated based on ab test config" def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() - assert !metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] - assert !metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] + assert !metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] + assert !metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] assert metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 assert metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 @@ -311,7 +310,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { flushMetrics(pbsServiceWithMultipleModules) and: "Save account with ab test config" - def ortb2AbTestConfig = AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + def ortb2AbTestConfig = AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { it.percentActive = MIN_PERCENT_AB } def richMediaAbTestConfig = AbTest.getDefault(PB_RESPONSE_CORRECTION.code).tap { @@ -329,14 +328,14 @@ class AbTestingModuleSpec extends ModuleBaseSpec { then: "PBS should apply ab test config for ortb2blocking module" def invocationResults = response?.ext?.prebid?.modules?.trace?.stages?.outcomes?.groups?.invocationResults?.flatten() as List - def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, ModuleName.PB_ORTB2_BLOCKING) + def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, PB_ORTB2_BLOCKING) verifyAll(ortbBlockingInvocationResults) { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "PBS should not apply ab test config for pb-response-correction module" @@ -345,15 +344,15 @@ class AbTestingModuleSpec extends ModuleBaseSpec { it.status == [SUCCESS] it.action == [NO_ACTION] it.analyticsTags.activities.name.flatten() == [AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.RUN] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.RUN] it.analyticsTags.activities.results.values.module.flatten() == [PB_RESPONSE_CORRECTION] } and: "Metric for skipped ortb2blocking module should be updated based on ab test config" def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 and: "Metric for allowed to run pb-response-correction module should be updated based on ab test config" assert metrics[CALL_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 @@ -371,7 +370,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code, [PBSUtils.randomNumber]).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code, [PBSUtils.randomNumber]).tap { percentActive = MIN_PERCENT_AB }] } @@ -388,15 +387,15 @@ class AbTestingModuleSpec extends ModuleBaseSpec { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "Metric for specified module should be updated based on ab test config" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 } def "PBS should apply a/b test config and run module when config is on max percentage or default value"() { @@ -408,7 +407,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { it.percentActive = percentActive it.percentActiveSnakeCase = percentActiveSnakeCase }] @@ -425,21 +424,21 @@ class AbTestingModuleSpec extends ModuleBaseSpec { verifyAll(invocationResults) { it.status == [SUCCESS, SUCCESS] it.action == [NO_ACTION, NO_ACTION] - it.analyticsTags.activities.name.flatten().sort() == [ORTB2_BLOCKING, AB_TESTING, AB_TESTING].value.sort() - it.analyticsTags.activities.status.flatten().sort() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS, FetchStatus.SUCCESS].sort() - it.analyticsTags.activities.results.status.flatten().sort() == [FetchStatus.SUCCESS_ALLOW, FetchStatus.RUN, FetchStatus.RUN].sort() - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.name.flatten().sort() == [ModuleActivityName.PB_ORTB2_BLOCKING, AB_TESTING, AB_TESTING].value.sort() + it.analyticsTags.activities.status.flatten().sort() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS].sort() + it.analyticsTags.activities.results.status.flatten().sort() == [AnalyticTagStatus.SUCCESS_ALLOW, AnalyticTagStatus.RUN, AnalyticTagStatus.RUN].sort() + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "Metric for specified module should be as default call" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] where: percentActive | percentActiveSnakeCase @@ -457,7 +456,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { it.percentActive = percentActive it.percentActiveSnakeCase = percentActiveSnakeCase }] @@ -475,15 +474,15 @@ class AbTestingModuleSpec extends ModuleBaseSpec { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "Metric for specified module should be updated based on ab test config" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 where: percentActive | percentActiveSnakeCase @@ -500,7 +499,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { it.percentActive = percentActive it.percentActiveSnakeCase = percentActiveSnakeCase }] @@ -522,15 +521,15 @@ class AbTestingModuleSpec extends ModuleBaseSpec { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "Metric for specified module should be updated based on ab test config" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 where: percentActive | percentActiveSnakeCase @@ -547,7 +546,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { it.percentActive = percentActive it.percentActiveSnakeCase = percentActiveSnakeCase }] @@ -569,21 +568,21 @@ class AbTestingModuleSpec extends ModuleBaseSpec { it.status == [SUCCESS, SUCCESS] it.action == [NO_ACTION, NO_ACTION] - it.analyticsTags.activities.name.flatten().sort() == [ORTB2_BLOCKING, AB_TESTING, AB_TESTING].value.sort() - it.analyticsTags.activities.status.flatten().sort() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS, FetchStatus.SUCCESS].sort() - it.analyticsTags.activities.results.status.flatten().sort() == [FetchStatus.SUCCESS_ALLOW, FetchStatus.RUN, FetchStatus.RUN].sort() - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.name.flatten().sort() == [ModuleActivityName.PB_ORTB2_BLOCKING, AB_TESTING, AB_TESTING].value.sort() + it.analyticsTags.activities.status.flatten().sort() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS].sort() + it.analyticsTags.activities.results.status.flatten().sort() == [AnalyticTagStatus.SUCCESS_ALLOW, AnalyticTagStatus.RUN, AnalyticTagStatus.RUN].sort() + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "Metric for specified module should be as default call" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] where: percentActive | percentActiveSnakeCase @@ -600,7 +599,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { percentActive = MIN_PERCENT_AB it.logAnalyticsTag = logAnalyticsTag it.logAnalyticsTagSnakeCase = logAnalyticsTagSnakeCase @@ -619,15 +618,15 @@ class AbTestingModuleSpec extends ModuleBaseSpec { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "Metric for specified module should be updated based on ab test config" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 where: logAnalyticsTag | logAnalyticsTagSnakeCase @@ -645,7 +644,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { percentActive = MIN_PERCENT_AB it.logAnalyticsTag = logAnalyticsTag it.logAnalyticsTagSnakeCase = logAnalyticsTagSnakeCase @@ -670,8 +669,8 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be updated based on ab test config" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 where: logAnalyticsTag | logAnalyticsTagSnakeCase @@ -688,7 +687,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { percentActive = MAX_PERCENT_AB it.logAnalyticsTag = logAnalyticsTag it.logAnalyticsTagSnakeCase = logAnalyticsTagSnakeCase @@ -713,13 +712,13 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be as default call" def metrics = ortbModulePbsService.sendCollectedMetricsRequest() - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] where: logAnalyticsTag | logAnalyticsTagSnakeCase @@ -736,7 +735,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, ORTB_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { percentActive = PBSUtils.getRandomNumber(MIN_PERCENT_AB, MAX_PERCENT_AB) }] } @@ -766,7 +765,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { def "PBS should apply a/b test config from host config when accounts is not specified when account config and default account doesn't include a/b test config"() { given: "PBS service with specific ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, MODULES_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code, accouns).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code, accouns).tap { percentActive = MIN_PERCENT_AB }] } @@ -784,14 +783,14 @@ class AbTestingModuleSpec extends ModuleBaseSpec { then: "PBS should apply ab test config for specified module" def invocationResults = response?.ext?.prebid?.modules?.trace?.stages?.outcomes?.groups?.invocationResults?.flatten() as List - def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, ModuleName.PB_ORTB2_BLOCKING) + def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, PB_ORTB2_BLOCKING) verifyAll(ortbBlockingInvocationResults) { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "PBS should not apply ab test config for other module" @@ -805,8 +804,8 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be updated based on ab test config" def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 and: "Metric for non specified module should be as default call" assert metrics[CALL_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 @@ -815,9 +814,6 @@ class AbTestingModuleSpec extends ModuleBaseSpec { assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - where: accouns << [null, []] } @@ -826,7 +822,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { given: "PBS service with specific ab test config" def accountId = PBSUtils.randomNumber def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, MODULES_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code, [PBSUtils.randomNumber, accountId]).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code, [PBSUtils.randomNumber, accountId]).tap { percentActive = MIN_PERCENT_AB }] } @@ -847,14 +843,14 @@ class AbTestingModuleSpec extends ModuleBaseSpec { then: "PBS should apply ab test config for specified module" def invocationResults = response?.ext?.prebid?.modules?.trace?.stages?.outcomes?.groups?.invocationResults?.flatten() as List - def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, ModuleName.PB_ORTB2_BLOCKING) + def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, PB_ORTB2_BLOCKING) verifyAll(ortbBlockingInvocationResults) { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "PBS should not apply ab test config for other module" @@ -868,8 +864,8 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be updated based on ab test config" def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 and: "Metric for non specified module should be as default call" assert metrics[CALL_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 @@ -877,15 +873,12 @@ class AbTestingModuleSpec extends ModuleBaseSpec { assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should apply a/b test config from host config for specific account and general config when account config and default account doesn't include a/b test config"() { given: "PBS service with specific ab test config" def accountId = PBSUtils.randomNumber - def ortb2AbTestConfig = AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code, []).tap { + def ortb2AbTestConfig = AbTest.getDefault(PB_ORTB2_BLOCKING.code, []).tap { it.percentActive = MIN_PERCENT_AB } def richMediaAbTestConfig = AbTest.getDefault(PB_RESPONSE_CORRECTION.code, [accountId]).tap { @@ -911,14 +904,14 @@ class AbTestingModuleSpec extends ModuleBaseSpec { then: "PBS should apply ab test config for ortb2blocking module" def invocationResults = response?.ext?.prebid?.modules?.trace?.stages?.outcomes?.groups?.invocationResults?.flatten() as List - def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, ModuleName.PB_ORTB2_BLOCKING) + def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, PB_ORTB2_BLOCKING) verifyAll(ortbBlockingInvocationResults) { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "PBS should apply ab test config for pb-response-correction module" @@ -927,15 +920,15 @@ class AbTestingModuleSpec extends ModuleBaseSpec { it.status == [SUCCESS] it.action == [NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED] it.analyticsTags.activities.results.values.module.flatten() == [PB_RESPONSE_CORRECTION] } and: "Metric for skipped pb-ortb2blocking module should be updated based on ab test config" def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() - assert !metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] - assert !metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] + assert !metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] + assert !metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] assert metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 assert metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 @@ -944,15 +937,12 @@ class AbTestingModuleSpec extends ModuleBaseSpec { assert !metrics[CALL_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] assert metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 assert metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS shouldn't apply a/b test config from host config for non specified accounts when account config and default account doesn't include a/b test config"() { given: "PBS service with specific ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, MODULES_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code, [PBSUtils.randomNumber]).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code, [PBSUtils.randomNumber]).tap { percentActive = MIN_PERCENT_AB }] } @@ -970,14 +960,14 @@ class AbTestingModuleSpec extends ModuleBaseSpec { then: "PBS should apply ab test config for specified module" def invocationResults = response?.ext?.prebid?.modules?.trace?.stages?.outcomes?.groups?.invocationResults?.flatten() as List - def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, ModuleName.PB_ORTB2_BLOCKING) + def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, PB_ORTB2_BLOCKING) verifyAll(ortbBlockingInvocationResults) { it.status == [SUCCESS, SUCCESS] it.action == [NO_ACTION, NO_ACTION] - it.analyticsTags.activities.name.flatten() == [ORTB2_BLOCKING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SUCCESS_ALLOW] + it.analyticsTags.activities.name.flatten() == [ModuleActivityName.PB_ORTB2_BLOCKING].value + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SUCCESS_ALLOW] it.analyticsTags.activities.results.values.module.flatten().every { it == null } } @@ -992,13 +982,13 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be as default call" def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[CALL_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] - assert !metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] + assert !metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] and: "Metric for non specified module should be as default call" assert metrics[CALL_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 @@ -1006,15 +996,12 @@ class AbTestingModuleSpec extends ModuleBaseSpec { assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should prioritise a/b test config from default account and only specified module when host and default account contains a/b test configs"() { given: "PBS service with specific ab test config" def accountExecutionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, MODULES_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { percentActive = MIN_PERCENT_AB }] } @@ -1023,7 +1010,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { } def hostExecutionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, MODULES_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code)] + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code)] } def pbsConfig = MULTI_MODULE_CONFIG + ['hooks.host-execution-plan': encode(hostExecutionPlan)] + ["settings.default-account-config": encode(defaultAccountConfigSettings)] @@ -1040,14 +1027,14 @@ class AbTestingModuleSpec extends ModuleBaseSpec { then: "PBS should apply ab test config for specified module and call it based on all execution plans" def invocationResults = response?.ext?.prebid?.modules?.trace?.stages?.outcomes?.groups?.invocationResults?.flatten() as List - def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, ModuleName.PB_ORTB2_BLOCKING) + def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, PB_ORTB2_BLOCKING) verifyAll(ortbBlockingInvocationResults) { it.status == [SUCCESS, SUCCESS, SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION, NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING, AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS, FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED, FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "PBS should not apply ab test config for other modules and call them based on all execution plans" @@ -1061,8 +1048,8 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be updated based on ab test config" def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 2 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 2 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 2 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 2 and: "Metric for non specified module should be as default call" assert metrics[CALL_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 2 @@ -1070,15 +1057,12 @@ class AbTestingModuleSpec extends ModuleBaseSpec { assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should prioritise a/b test config from account over default account and only specified module when specific account and default account contains a/b test configs"() { given: "PBS service with specific ab test config" def accountExecutionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, MODULES_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code)] + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code)] } def defaultAccountConfigSettings = AccountConfig.defaultAccountConfig.tap { hooks = new AccountHooksConfiguration(executionPlan: accountExecutionPlan) @@ -1096,7 +1080,7 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Save account with ab test config" def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, MODULES_STAGES).tap { - abTests = [AbTest.getDefault(ModuleName.PB_ORTB2_BLOCKING.code).tap { + abTests = [AbTest.getDefault(PB_ORTB2_BLOCKING.code).tap { percentActive = MIN_PERCENT_AB }] } @@ -1111,14 +1095,14 @@ class AbTestingModuleSpec extends ModuleBaseSpec { def invocationResults = response?.ext?.prebid?.modules?.trace?.stages?.outcomes?.groups?.invocationResults?.flatten() as List and: "PBS should apply ab test config for specified module" - def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, ModuleName.PB_ORTB2_BLOCKING) + def ortbBlockingInvocationResults = filterInvocationResultsByModule(invocationResults, PB_ORTB2_BLOCKING) verifyAll(ortbBlockingInvocationResults) { it.status == [SUCCESS, SUCCESS] it.action == [NO_INVOCATION, NO_INVOCATION] it.analyticsTags.activities.name.flatten() == [AB_TESTING, AB_TESTING].value - it.analyticsTags.activities.status.flatten() == [FetchStatus.SUCCESS, FetchStatus.SUCCESS] - it.analyticsTags.activities.results.status.flatten() == [FetchStatus.SKIPPED, FetchStatus.SKIPPED] - it.analyticsTags.activities.results.values.module.flatten() == [ModuleName.PB_ORTB2_BLOCKING, ModuleName.PB_ORTB2_BLOCKING] + it.analyticsTags.activities.status.flatten() == [AnalyticTagStatus.SUCCESS, AnalyticTagStatus.SUCCESS] + it.analyticsTags.activities.results.status.flatten() == [AnalyticTagStatus.SKIPPED, AnalyticTagStatus.SKIPPED] + it.analyticsTags.activities.results.values.module.flatten() == [PB_ORTB2_BLOCKING, PB_ORTB2_BLOCKING] } and: "PBS should not apply ab test config for other module" @@ -1132,8 +1116,8 @@ class AbTestingModuleSpec extends ModuleBaseSpec { and: "Metric for specified module should be updated based on ab test config" def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 - assert metrics[NO_INVOCATION_METRIC(ModuleName.PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 + assert metrics[NO_INVOCATION_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 and: "Metric for non specified module should be as default call" assert metrics[CALL_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] == 1 @@ -1141,9 +1125,6 @@ class AbTestingModuleSpec extends ModuleBaseSpec { assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] assert !metrics[NO_INVOCATION_METRIC(PB_RESPONSE_CORRECTION, ALL_PROCESSED_BID_RESPONSES)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } private static List filterInvocationResultsByModule(List invocationResults, ModuleName moduleName) { diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/GeneralModuleSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/GeneralModuleSpec.groovy index d883da8f219..030a6797ea1 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/GeneralModuleSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/GeneralModuleSpec.groovy @@ -15,7 +15,9 @@ import org.prebid.server.functional.model.request.auction.TraceLevel import org.prebid.server.functional.model.response.auction.InvocationResult import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService -import org.prebid.server.functional.util.PBSUtils +import org.prebid.server.functional.testcontainers.PbsServiceFactory +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig +import spock.lang.IgnoreRest import java.time.Instant @@ -32,6 +34,7 @@ import static org.prebid.server.functional.model.config.Stage.RAW_BIDDER_RESPONS import static org.prebid.server.functional.model.request.auction.BidRequest.getDefaultBidRequest import static org.prebid.server.functional.model.response.auction.InvocationStatus.SUCCESS import static org.prebid.server.functional.model.response.auction.ResponseAction.NO_ACTION +import static org.prebid.server.functional.testcontainers.PbsServiceFactory.ContainerPolicy.PERSISTENT class GeneralModuleSpec extends ModuleBaseSpec { @@ -43,13 +46,12 @@ class GeneralModuleSpec extends ModuleBaseSpec { private final static Map> RESPONSE_STAGES = [(ALL_PROCESSED_BID_RESPONSES): [PB_RICHMEDIA_FILTER]] private final static Map> MODULES_STAGES = ORTB_STAGES + RESPONSE_STAGES private final static ExecutionPlan GLOBAL_EXECUTION_PLAN = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, MODULES_STAGES) - private final static Map MULTI_MODULE_CONFIG = getRichMediaFilterSettings(PBSUtils.randomString) + - getOrtb2BlockingSettings() + - ['settings.enforce-valid-account': 'true', - 'hooks.host-execution-plan' : encode(GLOBAL_EXECUTION_PLAN)] + private final static PbsContainerConfig MULTI_MODULE_CONFIG = getModuleBaseSettings(PB_RICHMEDIA_FILTER) + + getModuleBaseSettings(PB_ORTB2_BLOCKING) + + ['settings.enforce-valid-account': 'true', 'hooks.host-execution-plan': encode(GLOBAL_EXECUTION_PLAN)] - private static final PrebidServerService pbsServiceWithMultipleModule = pbsServiceFactory.getService(MULTI_MODULE_CONFIG + DISABLED_INVOKE_CONFIG) - private static final PrebidServerService pbsServiceWithMultipleModuleWithRequireInvoke = pbsServiceFactory.getService(MULTI_MODULE_CONFIG + ENABLED_INVOKE_CONFIG) + private static final PrebidServerService pbsServiceWithMultipleModule = pbsServiceFactory.getService(MULTI_MODULE_CONFIG + DISABLED_INVOKE_CONFIG, PERSISTENT) + private static final PrebidServerService pbsServiceWithMultipleModuleWithRequireInvoke = pbsServiceFactory.getService(MULTI_MODULE_CONFIG + ENABLED_INVOKE_CONFIG, PERSISTENT) def cleanupSpec() { pbsServiceFactory.removeContainer(MULTI_MODULE_CONFIG + DISABLED_INVOKE_CONFIG) @@ -182,9 +184,6 @@ class GeneralModuleSpec extends ModuleBaseSpec { and: "RB-Richmedia-Filter module call metrics should be updated" assert metrics[CALL_METRIC(PB_RICHMEDIA_FILTER, ALL_PROCESSED_BID_RESPONSES)] == 1 assert metrics[NOOP_METRIC(PB_RICHMEDIA_FILTER, ALL_PROCESSED_BID_RESPONSES)] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should call all modules and traces response when account includes modules config and require-config-to-invoke is enabled"() { @@ -338,9 +337,6 @@ class GeneralModuleSpec extends ModuleBaseSpec { assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 assert metrics[NOOP_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 assert metrics[NOOP_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS shouldn't call module when disabled in host config and no account config provided"() { @@ -373,9 +369,6 @@ class GeneralModuleSpec extends ModuleBaseSpec { assert !metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] assert !metrics[NOOP_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] assert !metrics[NOOP_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS shouldn't call module and not override host config when default-account module-execution config enabled module"() { @@ -412,9 +405,6 @@ class GeneralModuleSpec extends ModuleBaseSpec { assert !metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] assert !metrics[NOOP_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] assert !metrics[NOOP_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should call module without account module config when default-account module-execution config enabling module"() { @@ -454,9 +444,6 @@ class GeneralModuleSpec extends ModuleBaseSpec { assert metrics[CALL_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 assert metrics[NOOP_METRIC(PB_ORTB2_BLOCKING, BIDDER_REQUEST)] == 1 assert metrics[NOOP_METRIC(PB_ORTB2_BLOCKING, RAW_BIDDER_RESPONSE)] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS shouldn't call any modules without account config when default-account module-execution config not enabling module"() { @@ -497,9 +484,6 @@ class GeneralModuleSpec extends ModuleBaseSpec { assert !metrics[CALL_METRIC(PB_RICHMEDIA_FILTER, ALL_PROCESSED_BID_RESPONSES)] assert !metrics[NOOP_METRIC(PB_RICHMEDIA_FILTER, ALL_PROCESSED_BID_RESPONSES)] - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - where: moduleExecutionStatus << [false, null] } @@ -545,9 +529,6 @@ class GeneralModuleSpec extends ModuleBaseSpec { and: "RB-Richmedia-Filter module call metrics shouldn't be updated" assert !metrics[CALL_METRIC(PB_RICHMEDIA_FILTER, ALL_PROCESSED_BID_RESPONSES)] assert !metrics[NOOP_METRIC(PB_RICHMEDIA_FILTER, ALL_PROCESSED_BID_RESPONSES)] - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should merge account level config without any errors when config contains proper request methods"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy index da5057d472b..9607dcd9247 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy @@ -1,31 +1,80 @@ package org.prebid.server.functional.tests.module -import org.prebid.server.functional.model.config.ModuleName -import org.prebid.server.functional.model.config.Endpoint +import org.prebid.server.functional.model.bidder.BidderName +import org.prebid.server.functional.model.config.AccountConfig +import org.prebid.server.functional.model.config.AccountHooksConfiguration import org.prebid.server.functional.model.config.ExecutionPlan import org.prebid.server.functional.model.config.HookHttpEndpoint +import org.prebid.server.functional.model.config.ModuleName +import org.prebid.server.functional.model.config.PbsModulesConfig import org.prebid.server.functional.model.config.Stage +import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.response.auction.AnalyticResult import org.prebid.server.functional.model.response.auction.BidResponse +import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.tests.BaseSpec import org.prebid.server.functional.util.PBSUtils +import static org.prebid.server.functional.model.bidder.BidderName.AMX +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC +import static org.prebid.server.functional.model.bidder.BidderName.IX +import static org.prebid.server.functional.model.bidder.BidderName.OPENX +import static org.prebid.server.functional.model.bidder.BidderName.OPENX_ALIAS +import static org.prebid.server.functional.model.config.HookHttpEndpoint.AUCTION import static org.prebid.server.functional.model.config.ModuleName.OPTABLE_TARGETING import static org.prebid.server.functional.model.config.ModuleName.PB_ORTB2_BLOCKING import static org.prebid.server.functional.model.config.ModuleName.PB_REQUEST_CORRECTION import static org.prebid.server.functional.model.config.ModuleName.PB_RESPONSE_CORRECTION import static org.prebid.server.functional.model.config.ModuleName.PB_RICHMEDIA_FILTER import static org.prebid.server.functional.model.config.ModuleName.PB_RULE_ENGINE -import static org.prebid.server.functional.model.config.HookHttpEndpoint.AUCTION -import static org.prebid.server.functional.model.config.Stage.ALL_PROCESSED_BID_RESPONSES -import static org.prebid.server.functional.model.config.Stage.PROCESSED_AUCTION_REQUEST import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer +import static org.prebid.server.functional.util.privacy.TcfConsent.GENERIC_VENDOR_ID class ModuleBaseSpec extends BaseSpec { + protected static final String WILDCARD = '*' + protected static final String RANDOM_DATACENTER_REGION = PBSUtils.randomString + protected static final Integer OPENX_VENDOR_ID = PBSUtils.getRandomNumber(0, 65534) + protected static final Integer AMX_VENDOR_ID = PBSUtils.getRandomNumber(0, 65534) + + protected static final Map GENERIC_CONFIG = [ + ("adapters.${GENERIC.value}.usersync.redirect.url".toString()) : "$networkServiceContainer.rootUri/generic-usersync".toString(), + ("adapters.${GENERIC.value}.usersync.redirect.support-cors".toString()): 'false', + ("adapters.${GENERIC.value}.meta-info.vendor-id".toString()) : GENERIC_VENDOR_ID.toString()] + + protected static final Map IX_CONFIG = getAdapterConfig(IX) + protected static final Map OPENX_CONFIG = getAdapterConfig(OPENX, OPENX_VENDOR_ID) + protected static final Map OPENX_ALIAS_CONFIG = getAdapterConfig(OPENX, OPENX_ALIAS, OPENX_VENDOR_ID) + protected static final Map AMX_CONFIG = getAdapterConfig(AMX, AMX_VENDOR_ID) + + private static final Map ENABLED_DEBUG_LOG_MODE = ["logging.level.root": "debug"] + + private static final Map ORTB_ADAPTER_CONFIG = ['adapter-defaults.ortb.multiformat-supported': 'false'] + + private static final Map MODIFYING_VAST_CONFIG = ["adapter-defaults.modifying-vast-xml-allowed": "false", + "adapters.generic.modifying-vast-xml-allowed": "false"] + + private static final Map CACHE_STORAGE_CONFIG = ['storage.pbc.path' : 'stored-cache', + 'storage.pbc.call-timeout-ms': '1000', + 'storage.pbc.enabled' : 'true', + 'cache.module.enabled' : 'true', + 'pbc.api.key' : PBSUtils.randomString, + 'cache.api-key-secured' : 'false'] + + protected final static PbsContainerConfig EXTERNAL_MODULES_CONFIG = getModuleBaseSettings(PB_RICHMEDIA_FILTER) + + getModuleBaseSettings(PB_RESPONSE_CORRECTION) + + getModuleBaseSettings(PB_ORTB2_BLOCKING) + + getModuleBaseSettings(PB_REQUEST_CORRECTION) + + getOptableTargetingSettings() + + getRulesEngineSettings() + + protected static PrebidServerService pbsServiceWithMultipleModules + def setupSpec() { prebidCache.setResponse() bidder.setResponse() + pbsServiceWithMultipleModules = pbsServiceFactory.getService(getDefaultMultipleModulesConfig()) } def cleanupSpec() { @@ -50,59 +99,77 @@ class ModuleBaseSpec extends BaseSpec { "modules.module.${module.code}.stage.${stage.metricValue}.hook.${module.code}-${stage.value}-hook.execution-error" } - protected static Map getResponseCorrectionConfig(HookHttpEndpoint endpoint = AUCTION) { - ["hooks.${PB_RESPONSE_CORRECTION.code}.enabled": true, - "hooks.host-execution-plan" : encode(ExecutionPlan.getSingleEndpointExecutionPlan(endpoint, [(ALL_PROCESSED_BID_RESPONSES): [PB_RESPONSE_CORRECTION]]))] - .collectEntries { key, value -> [(key.toString()): value.toString()] } + protected PbsContainerConfig getDefaultMultipleModulesConfig() { + EXTERNAL_MODULES_CONFIG + + EMPTY_CACHE_TTL_CONFIG + + ENABLED_DEBUG_LOG_MODE + + ORTB_ADAPTER_CONFIG + + MODIFYING_VAST_CONFIG + + CACHE_STORAGE_CONFIG + + GENERIC_CONFIG + + IX_CONFIG + + AMX_CONFIG + + OPENX_CONFIG + + OPENX_ALIAS_CONFIG + + ['datacenter-region': RANDOM_DATACENTER_REGION] } - protected static Map getRichMediaFilterSettings(String scriptPattern, - Boolean filterMraidEnabled = true, - HookHttpEndpoint endpoint = AUCTION) { + protected static PbsContainerConfig getModuleBaseSettings(ModuleName name, boolean enabled = true) { + new PbsContainerConfig([("hooks.${name.code}.enabled".toString()): enabled.toString()]) + } - ["hooks.${PB_RICHMEDIA_FILTER.code}.enabled" : true, - "hooks.modules.${PB_RICHMEDIA_FILTER.code}.mraid-script-pattern": scriptPattern, - "hooks.modules.${PB_RICHMEDIA_FILTER.code}.filter-mraid" : filterMraidEnabled, - "hooks.host-execution-plan" : encode(ExecutionPlan.getSingleEndpointExecutionPlan(endpoint, [(ALL_PROCESSED_BID_RESPONSES): [PB_RICHMEDIA_FILTER]]))] - .findAll { it.value != null } - .collectEntries { key, value -> [(key.toString()): value.toString()] } + protected static PbsContainerConfig getRichMediaFilterSettings(String scriptPattern, + boolean filterMraidEnabled = true) { + new PbsContainerConfig([ + "hooks.${PB_RICHMEDIA_FILTER.code}.enabled" : true, + "hooks.modules.${PB_RICHMEDIA_FILTER.code}.mraid-script-pattern": scriptPattern, + "hooks.modules.${PB_RICHMEDIA_FILTER.code}.filter-mraid" : filterMraidEnabled, + ]) } - protected static Map getDisabledRichMediaFilterSettings(String scriptPattern, - boolean filterMraidEnabled = true) { - ["hooks.${PB_RICHMEDIA_FILTER.code}.enabled" : false, - "hooks.modules.${PB_RICHMEDIA_FILTER.code}.mraid-script-pattern": scriptPattern, - "hooks.modules.${PB_RICHMEDIA_FILTER.code}.filter-mraid" : filterMraidEnabled] - .collectEntries { key, value -> [(key.toString()): value.toString()] } + protected static PbsContainerConfig getOptableTargetingSettings(boolean isEnabled = true) { + new PbsContainerConfig([ + "hooks.${OPTABLE_TARGETING.code}.enabled" : isEnabled.toString(), + "hooks.modules.${OPTABLE_TARGETING.code}.api-endpoint": "${networkServiceContainer.rootUri}/stored-cache", + "hooks.modules.${OPTABLE_TARGETING.code}.tenant" : PBSUtils.randomString, + "hooks.modules.${OPTABLE_TARGETING.code}.origin" : PBSUtils.randomString + ]) } - protected static Map getOptableTargetingSettings(boolean isEnabled = true, HookHttpEndpoint endpoint = AUCTION) { - ["hooks.${OPTABLE_TARGETING.code}.enabled" : isEnabled as String, - "hooks.modules.${OPTABLE_TARGETING.code}.api-endpoint": "$networkServiceContainer.rootUri/stored-cache".toString(), - "hooks.modules.${OPTABLE_TARGETING.code}.tenant" : PBSUtils.randomString, - "hooks.modules.${OPTABLE_TARGETING.code}.origin" : PBSUtils.randomString, - "hooks.host-execution-plan" : encode(ExecutionPlan.getSingleEndpointExecutionPlan(endpoint, [(PROCESSED_AUCTION_REQUEST): [OPTABLE_TARGETING]]))] - .collectEntries { key, value -> [(key.toString()): value.toString()] } + protected static PbsContainerConfig getRulesEngineSettings() { + new PbsContainerConfig([ + "hooks.${PB_RULE_ENGINE.code}.enabled" : "true", + "hooks.${PB_RULE_ENGINE.code}.rule-cache.expire-after-minutes" : "10000", + "hooks.${PB_RULE_ENGINE.code}.rule-cache.max-size" : "20000", + "hooks.${PB_RULE_ENGINE.code}.rule-parsing.retry-initial-delay-millis": "10000", + "hooks.${PB_RULE_ENGINE.code}.rule-parsing.retry-max-delay-millis" : "10000", + "hooks.${PB_RULE_ENGINE.code}.rule-parsing.retry-exponential-factor" : "1.2", + "hooks.${PB_RULE_ENGINE.code}.rule-parsing.retry-exponential-jitter" : "1.2" + ]) } - protected static Map getOrtb2BlockingSettings(boolean isEnabled = true) { - ["hooks.${PB_ORTB2_BLOCKING.code}.enabled": isEnabled as String] + private static Map getAdapterConfig(BidderName bidder, Integer vendorId = null) { + [ + "adapters.${bidder.value}.enabled" : 'true', + "adapters.${bidder.value}.endpoint": "${networkServiceContainer.rootUri}/auction" + ] + (vendorId != null ? ["adapters.${bidder.value}.meta-info.vendor-id": vendorId] : [:]) } - protected static Map getRequestCorrectionSettings(HookHttpEndpoint endpoint = AUCTION, Stage stage = PROCESSED_AUCTION_REQUEST) { - ["hooks.${PB_REQUEST_CORRECTION.code}.enabled": "true", - "hooks.host-execution-plan" : encode(ExecutionPlan.getSingleEndpointExecutionPlan(endpoint, PB_REQUEST_CORRECTION, [stage]))] + private static Map getAdapterConfig(BidderName bidder, BidderName alias, Integer vendorId = null) { + [ + "adapters.${bidder.value}.aliases.${alias.value}.enabled" : 'true', + "adapters.${bidder.value}.aliases.${alias.value}.endpoint": "${networkServiceContainer.rootUri}/auction" + ] + (vendorId != null ? ["adapters.${bidder.value}.aliases.${alias.value}.meta-info.vendor-id": vendorId] : [:]) } - protected static Map getRulesEngineSettings(HookHttpEndpoint endpoint = AUCTION, Stage stage = PROCESSED_AUCTION_REQUEST) { - ["hooks.${PB_RULE_ENGINE.code}.enabled" : "true", - "hooks.${PB_RULE_ENGINE.code}.rule-cache.expire-after-minutes" : "10000", - "hooks.${PB_RULE_ENGINE.code}.rule-cache.max-size" : "20000", - "hooks.${PB_RULE_ENGINE.code}.rule-parsing.retry-initial-delay-millis": "10000", - "hooks.${PB_RULE_ENGINE.code}.rule-parsing.retry-max-delay-millis" : "10000", - "hooks.${PB_RULE_ENGINE.code}.rule-parsing.retry-exponential-factor" : "1.2", - "hooks.${PB_RULE_ENGINE.code}.rule-parsing.retry-exponential-jitter" : "1.2", - "hooks.host-execution-plan" : encode(ExecutionPlan.getSingleEndpointExecutionPlan(endpoint, PB_RULE_ENGINE, [stage]))] + protected static Account getAccountWithModuleConfig(String accountId, + Map> modulesStages, + HookHttpEndpoint endpoint = AUCTION) { + + def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(endpoint, modulesStages) + def accountHooksConfig = new AccountHooksConfiguration(executionPlan: executionPlan, modules: new PbsModulesConfig()) + def accountConfig = new AccountConfig(hooks: accountHooksConfig) + new Account(uuid: accountId, config: accountConfig) } protected static List getAnalyticResults(BidResponse response) { diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/analyticstag/AnalyticsTagsModuleSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/analyticstag/AnalyticsTagsModuleSpec.groovy index dfd34bccb86..034d10f311c 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/analyticstag/AnalyticsTagsModuleSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/analyticstag/AnalyticsTagsModuleSpec.groovy @@ -9,13 +9,12 @@ import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.db.StoredResponse import org.prebid.server.functional.model.request.auction.AnalyticsOptions import org.prebid.server.functional.model.request.auction.BidRequest -import org.prebid.server.functional.model.request.auction.FetchStatus +import org.prebid.server.functional.model.request.auction.AnalyticTagStatus import org.prebid.server.functional.model.request.auction.PrebidAnalytics import org.prebid.server.functional.model.request.auction.RichmediaFilter import org.prebid.server.functional.model.request.auction.StoredBidResponse import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ModuleActivityName -import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.tests.module.ModuleBaseSpec import org.prebid.server.functional.util.PBSUtils @@ -30,13 +29,7 @@ import static org.prebid.server.functional.model.response.auction.ErrorType.PREB class AnalyticsTagsModuleSpec extends ModuleBaseSpec { - private static final PrebidServerService pbsServiceWithEnabledOrtb2Blocking = pbsServiceFactory.getService(getOrtb2BlockingSettings()) - - def cleanupSpec() { - pbsServiceFactory.removeContainer(getOrtb2BlockingSettings()) - } - - def "PBS should include analytics tag for pb-ortb2-blocking module in response when request and account allow client details"() { + def "PBS should include analytics tag for ortb2-blocking module in response when request and account allow client details"() { given: "Default account with module config" def bidRequest = BidRequest.defaultBidRequest.tap { it.ext.prebid.analytics = new PrebidAnalytics(options: new AnalyticsOptions(enableClientDetails: true)) @@ -50,7 +43,7 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - def bidResponse = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain ext.prebid.analyticsTags with module record" def analyticsTagPrebid = bidResponse.ext.prebid.analytics.tags.first @@ -59,12 +52,12 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { and: "Analytics tag should contain results with name and success status" def analyticResult = analyticsTagPrebid.analyticsTags.activities.first - assert analyticResult.status == FetchStatus.SUCCESS - assert analyticResult.name == ModuleActivityName.ORTB2_BLOCKING + assert analyticResult.status == AnalyticTagStatus.SUCCESS + assert analyticResult.name == ModuleActivityName.PB_ORTB2_BLOCKING and: "Should include appliedTo information in analytics tags results" verifyAll(analyticResult.results.first) { - it.status == FetchStatus.SUCCESS_ALLOW + it.status == AnalyticTagStatus.SUCCESS_ALLOW it.appliedTo.bidders == [GENERIC.value] it.appliedTo.impIds == bidRequest.imp.id } @@ -91,12 +84,10 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { storedResponseDao.save(storedResponse) and: "Account in the DB with cofig" - def richmediaFilter = new RichmediaFilter(filterMraid: true, mraidScriptPattern: PATTERN_NAME) - def richMediaFilterConfig = new PbsModulesConfig(pbRichmediaFilter: richmediaFilter) - def accountHooksConfig = new AccountHooksConfiguration(modules: richMediaFilterConfig) - def accountAnalyticsConfig = new AccountAnalyticsConfig(allowClientDetails: true) - def accountConfig = new AccountConfig(hooks: accountHooksConfig, analytics: accountAnalyticsConfig) - def account = new Account(uuid: bidRequest.accountId, config: accountConfig) + def account = (getAccountWithModuleConfig(bidRequest.accountId, [(ALL_PROCESSED_BID_RESPONSES): [PB_RICHMEDIA_FILTER]])).tap { + it.config.hooks.modules.pbRichmediaFilter = new RichmediaFilter(filterMraid: true, mraidScriptPattern: PATTERN_NAME) + it.config.analytics = new AccountAnalyticsConfig(allowClientDetails: true) + } accountDao.save(account) when: "PBS processes auction request" @@ -109,15 +100,18 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { and: "Analytics tag should contain results with name and success status" def analyticResult = analyticsTagPrebid.analyticsTags.activities.first - assert analyticResult.status == FetchStatus.SUCCESS + assert analyticResult.status == AnalyticTagStatus.SUCCESS assert analyticResult.name == ModuleActivityName.REJECT_RICHMEDIA and: "Should include appliedTo information in analytics tags results" verifyAll(analyticResult.results.first) { - it.status == FetchStatus.SUCCESS_BLOCK + it.status == AnalyticTagStatus.SUCCESS_BLOCK it.appliedTo.bidders == [GENERIC.value] it.appliedTo.impIds == bidRequest.imp.id } + +// cleanup: "Stop and remove pbs container" +// pbsServiceFactory.removeContainer(getRichMediaFilterSettings(PATTERN_NAME)) } def "PBS should include analytics tag in response when request and default account allow client details"() { @@ -127,7 +121,7 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { def accountConfig = new AccountConfig(hooks: hooksConfiguration, analytics: new AccountAnalyticsConfig(allowClientDetails: true)) and: "Prebid server with proper default account" - def pbsConfig = ['settings.default-account-config': encode(accountConfig)] + ortb2BlockingSettings + def pbsConfig = getModuleBaseSettings(PB_ORTB2_BLOCKING) + ['settings.default-account-config': encode(accountConfig)] def pbsServiceWithDefaultAccount = pbsServiceFactory.getService(pbsConfig) and: "Bid request with enabled client details" @@ -145,18 +139,15 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { and: "Analytics tag should contain results with name and success status" def analyticResult = analyticsTagPrebid.analyticsTags.activities.first - assert analyticResult.status == FetchStatus.SUCCESS - assert analyticResult.name == ModuleActivityName.ORTB2_BLOCKING + assert analyticResult.status == AnalyticTagStatus.SUCCESS + assert analyticResult.name == ModuleActivityName.PB_ORTB2_BLOCKING and: "Should include appliedTo information in analytics tags results" verifyAll(analyticResult.results.first) { - it.status == FetchStatus.SUCCESS_ALLOW + it.status == AnalyticTagStatus.SUCCESS_ALLOW it.appliedTo.bidders == [GENERIC.value] it.appliedTo.impIds == bidRequest.imp.id } - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should include analytics tag in response when request and account allow client details but default doesn't"() { @@ -166,7 +157,7 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { def defaultAccountConfig = new AccountConfig(hooks: defaultHooksConfiguration, analytics: new AccountAnalyticsConfig(allowClientDetails: false)) and: "Prebid server with proper default account" - def pbsConfig = ['settings.default-account-config': encode(defaultAccountConfig)] + ortb2BlockingSettings + def pbsConfig = getModuleBaseSettings(PB_ORTB2_BLOCKING) + ['settings.default-account-config': encode(defaultAccountConfig)] def pbsServiceWithDefaultAccount = pbsServiceFactory.getService(pbsConfig) and: "Bid request with enabled client details" @@ -191,18 +182,15 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { and: "Analytics tag should contain results with name and success status" def analyticResult = analyticsTagPrebid.analyticsTags.activities.first - assert analyticResult.status == FetchStatus.SUCCESS - assert analyticResult.name == ModuleActivityName.ORTB2_BLOCKING + assert analyticResult.status == AnalyticTagStatus.SUCCESS + assert analyticResult.name == ModuleActivityName.PB_ORTB2_BLOCKING and: "Should include appliedTo information in analytics tags results" verifyAll(analyticResult.results.first) { - it.status == FetchStatus.SUCCESS_ALLOW + it.status == AnalyticTagStatus.SUCCESS_ALLOW it.appliedTo.bidders == [GENERIC.value] it.appliedTo.impIds == bidRequest.imp.id } - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS should not include analytics tag in response without any warnings when timeout module disabled"() { @@ -242,7 +230,7 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - def bidResponse = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should not contain any analytics tag" assert !bidResponse?.ext?.prebid?.analytics?.tags @@ -265,7 +253,7 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - def bidResponse = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should not contain any analytics tag" assert !bidResponse?.ext?.prebid?.analytics?.tags @@ -289,7 +277,7 @@ class AnalyticsTagsModuleSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - def bidResponse = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should not contain any analytics tag" assert !bidResponse?.ext?.prebid?.analytics?.tags diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/optabletargeting/CacheStorageSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/optabletargeting/CacheStorageSpec.groovy index f3452ddd92d..aadd1303568 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/optabletargeting/CacheStorageSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/optabletargeting/CacheStorageSpec.groovy @@ -14,12 +14,13 @@ import org.prebid.server.functional.model.request.auction.Eid import org.prebid.server.functional.model.request.auction.Geo import org.prebid.server.functional.model.request.auction.PublicCountryIp import org.prebid.server.functional.model.request.auction.User -import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.scaffolding.StoredCache import org.prebid.server.functional.tests.module.ModuleBaseSpec import org.prebid.server.functional.util.PBSUtils -import static org.apache.commons.codec.binary.Base64.encodeBase64 +import static org.prebid.server.functional.model.config.Stage.PROCESSED_AUCTION_REQUEST + + import static org.apache.http.HttpStatus.SC_NOT_FOUND import static org.prebid.server.functional.model.config.ModuleName.OPTABLE_TARGETING import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer @@ -36,23 +37,6 @@ class CacheStorageSpec extends ModuleBaseSpec { private static final StoredCache storedCache = new StoredCache(networkServiceContainer) - private static final Map CACHE_STORAGE_CONFIG = ['storage.pbc.path' : 'stored-cache', - 'storage.pbc.call-timeout-ms': '1000', - 'storage.pbc.enabled' : 'true', - 'cache.module.enabled' : 'true', - 'pbc.api.key' : PBSUtils.randomString, - 'cache.api-key-secured' : 'false'] - private static final Map MODULE_STORAGE_CACHE_CONFIG = getOptableTargetingSettings() + CACHE_STORAGE_CONFIG - private static final PrebidServerService prebidServerStoredCacheService = pbsServiceFactory.getService(MODULE_STORAGE_CACHE_CONFIG) - - def setup() { - storedCache.reset() - } - - def cleanupSpec() { - pbsServiceFactory.removeContainer(MODULE_STORAGE_CACHE_CONFIG) - } - def "PBS should update error metrics when no cached requests present"() { given: "Default BidRequest with cache and device info" def randomIfa = PBSUtils.randomString @@ -65,13 +49,13 @@ class CacheStorageSpec extends ModuleBaseSpec { accountDao.save(account) and: "Flash metrics" - flushMetrics(prebidServerStoredCacheService) + flushMetrics(pbsServiceWithMultipleModules) when: "PBS processes auction request" - prebidServerStoredCacheService.sendAuctionRequest(bidRequest) + def s = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should update metrics for new saved text storage cache" - def metrics = prebidServerStoredCacheService.sendCollectedMetricsRequest() + def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() assert metrics[METRIC_CREATIVE_READ_ERR] == 1 and: "No updates for success metrics" @@ -96,13 +80,13 @@ class CacheStorageSpec extends ModuleBaseSpec { storedCache.setCachingResponse(SC_NOT_FOUND) and: "Flash metrics" - flushMetrics(prebidServerStoredCacheService) + flushMetrics(pbsServiceWithMultipleModules) when: "PBS processes auction request" - prebidServerStoredCacheService.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should update error metrics" - def metrics = prebidServerStoredCacheService.sendCollectedMetricsRequest() + def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() assert metrics[METRIC_CREATIVE_WRITE_ERR] == 1 and: "No updates for success metrics" @@ -111,7 +95,7 @@ class CacheStorageSpec extends ModuleBaseSpec { def "PBS should update metrics for new saved text storage cache when no cached requests"() { given: "Current value of metric prebid cache" - def okInitialValue = getCurrentMetricValue(prebidServerStoredCacheService, METRIC_CREATIVE_WRITE_OK) + def okInitialValue = getCurrentMetricValue(pbsServiceWithMultipleModules, METRIC_CREATIVE_WRITE_OK) and: "Default BidRequest with cache and device info" def randomIfa = PBSUtils.randomString @@ -124,17 +108,17 @@ class CacheStorageSpec extends ModuleBaseSpec { accountDao.save(account) and: "Mocked external request" - def targetingResult = storedCache.setTargetingResponse(bidRequest, targetingConfig) + storedCache.setTargetingResponse(bidRequest, targetingConfig) storedCache.setCachingResponse() and: "Flash metrics" - flushMetrics(prebidServerStoredCacheService) + flushMetrics(pbsServiceWithMultipleModules) when: "PBS processes auction request" - prebidServerStoredCacheService.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should update metrics for new saved text storage cache" - def metrics = prebidServerStoredCacheService.sendCollectedMetricsRequest() + def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() assert metrics[METRIC_CREATIVE_SIZE_TEXT] != 0 assert metrics[METRIC_CREATIVE_WRITE_OK] == okInitialValue + 1 @@ -144,11 +128,11 @@ class CacheStorageSpec extends ModuleBaseSpec { def "PBS should update metrics for stored cached requests cache when proper record present"() { given: "Current value of metric prebid cache" - def textInitialValue = getCurrentMetricValue(prebidServerStoredCacheService, METRIC_CREATIVE_SIZE_TEXT) - def ttlInitialValue = getCurrentMetricValue(prebidServerStoredCacheService, METRIC_CREATIVE_TTL_TEXT) - def writeInitialValue = getCurrentMetricValue(prebidServerStoredCacheService, METRIC_CREATIVE_WRITE_OK) - def readErrorInitialValue = getCurrentMetricValue(prebidServerStoredCacheService, METRIC_CREATIVE_READ_ERR) - def writeErrorInitialValue = getCurrentMetricValue(prebidServerStoredCacheService, METRIC_CREATIVE_WRITE_ERR) + def textInitialValue = getCurrentMetricValue(pbsServiceWithMultipleModules, METRIC_CREATIVE_SIZE_TEXT) + def ttlInitialValue = getCurrentMetricValue(pbsServiceWithMultipleModules, METRIC_CREATIVE_TTL_TEXT) + def writeInitialValue = getCurrentMetricValue(pbsServiceWithMultipleModules, METRIC_CREATIVE_WRITE_OK) + def readErrorInitialValue = getCurrentMetricValue(pbsServiceWithMultipleModules, METRIC_CREATIVE_READ_ERR) + def writeErrorInitialValue = getCurrentMetricValue(pbsServiceWithMultipleModules, METRIC_CREATIVE_WRITE_ERR) and: "Default BidRequest with cache and device info" def randomIfa = PBSUtils.randomString @@ -165,13 +149,13 @@ class CacheStorageSpec extends ModuleBaseSpec { storedCache.setCachingResponse() and: "Flash metrics" - flushMetrics(prebidServerStoredCacheService) + flushMetrics(pbsServiceWithMultipleModules) when: "PBS processes auction request" - prebidServerStoredCacheService.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should update metrics for stored cached requests" - def metrics = prebidServerStoredCacheService.sendCollectedMetricsRequest() + def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() assert metrics[METRIC_CREATIVE_READ_OK] == 1 and: "No updates for new saved text storage metrics" @@ -199,9 +183,8 @@ class CacheStorageSpec extends ModuleBaseSpec { private static Account createAccountWithRequestCorrectionConfig(BidRequest bidRequest, OptableTargetingConfig optableTargetingConfig) { - def pbsModulesConfig = new PbsModulesConfig(optableTargeting: optableTargetingConfig) - def accountHooksConfig = new AccountHooksConfiguration(modules: pbsModulesConfig) - def accountConfig = new AccountConfig(hooks: accountHooksConfig) - new Account(uuid: bidRequest.accountId, config: accountConfig) + getAccountWithModuleConfig(bidRequest.accountId, [(PROCESSED_AUCTION_REQUEST) : [OPTABLE_TARGETING]]).tap { + it.config.hooks.modules.optableTargeting = optableTargetingConfig + } } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbortb2blocking/PbOrtb2BlockingSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbortb2blocking/PbOrtb2BlockingSpec.groovy index 29e45b86955..4351fa61e5a 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbortb2blocking/PbOrtb2BlockingSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbortb2blocking/PbOrtb2BlockingSpec.groovy @@ -3,25 +3,21 @@ package org.prebid.server.functional.tests.module.pbortb2blocking import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.config.AccountAuctionConfig -import org.prebid.server.functional.model.config.AccountConfig -import org.prebid.server.functional.model.config.AccountHooksConfiguration -import org.prebid.server.functional.model.config.ExecutionPlan import org.prebid.server.functional.model.config.Ortb2BlockingActionOverride -import org.prebid.server.functional.model.config.Ortb2BlockingAttributeConfig import org.prebid.server.functional.model.config.Ortb2BlockingAttribute +import org.prebid.server.functional.model.config.Ortb2BlockingAttributeConfig import org.prebid.server.functional.model.config.Ortb2BlockingConditions import org.prebid.server.functional.model.config.Ortb2BlockingConfig import org.prebid.server.functional.model.config.Ortb2BlockingOverride -import org.prebid.server.functional.model.config.PbsModulesConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.Asset import org.prebid.server.functional.model.request.auction.Audio import org.prebid.server.functional.model.request.auction.Banner +import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.BidderControls import org.prebid.server.functional.model.request.auction.GenericPreferredBidder -import org.prebid.server.functional.model.request.auction.Ix -import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Imp +import org.prebid.server.functional.model.request.auction.Ix import org.prebid.server.functional.model.request.auction.Video import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.Bid @@ -29,19 +25,17 @@ import org.prebid.server.functional.model.response.auction.BidMediaType import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.MediaType import org.prebid.server.functional.model.response.auction.SeatBid -import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.tests.module.ModuleBaseSpec import org.prebid.server.functional.util.PBSUtils -import static org.prebid.server.functional.model.config.ModuleName.PB_ORTB2_BLOCKING import static org.prebid.server.functional.model.bidder.BidderName.ALIAS import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.bidder.BidderName.IX -import static org.prebid.server.functional.model.config.HookHttpEndpoint.AUCTION +import static org.prebid.server.functional.model.config.ModuleName.PB_ORTB2_BLOCKING import static org.prebid.server.functional.model.config.Ortb2BlockingAttribute.AUDIO_BATTR import static org.prebid.server.functional.model.config.Ortb2BlockingAttribute.BADV -import static org.prebid.server.functional.model.config.Ortb2BlockingAttribute.BAPP import static org.prebid.server.functional.model.config.Ortb2BlockingAttribute.BANNER_BATTR +import static org.prebid.server.functional.model.config.Ortb2BlockingAttribute.BAPP import static org.prebid.server.functional.model.config.Ortb2BlockingAttribute.BCAT import static org.prebid.server.functional.model.config.Ortb2BlockingAttribute.BTYPE import static org.prebid.server.functional.model.config.Ortb2BlockingAttribute.VIDEO_BATTR @@ -51,22 +45,9 @@ import static org.prebid.server.functional.model.response.auction.BidRejectionRe import static org.prebid.server.functional.model.response.auction.MediaType.AUDIO import static org.prebid.server.functional.model.response.auction.MediaType.BANNER import static org.prebid.server.functional.model.response.auction.MediaType.VIDEO -import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer class PbOrtb2BlockingSpec extends ModuleBaseSpec { - private static final String WILDCARD = '*' - private static final Map IX_CONFIG = ["adapters.ix.enabled" : "true", - "adapters.ix.endpoint": "$networkServiceContainer.rootUri/auction".toString()] - private static final Map PBS_CONFIG = getOrtb2BlockingSettings() + IX_CONFIG + - ['adapter-defaults.ortb.multiformat-supported': 'false'] - - private static final PrebidServerService pbsServiceWithEnabledOrtb2Blocking = pbsServiceFactory.getService(PBS_CONFIG) - - def cleanupSpec() { - pbsServiceFactory.removeContainer(PBS_CONFIG) - } - def "PBS should send original array ortb2 attribute to bidder when enforce blocking is disabled"() { given: "Default bid request with proper ortb attribute" def bidRequest = getBidRequestForOrtbAttribute(attributeName) @@ -82,7 +63,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request should contain proper ortb2 attributes from account config" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -121,7 +102,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes the auction request" - pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request should contain proper ortb2 attributes from account config" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -151,7 +132,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request shouldn't contain ortb2 attributes from account config for any media-type" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -196,7 +177,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request shouldn't contain ortb2 attributes from account config for any media-type" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -242,7 +223,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request shouldn't contain ortb2 attributes from account config for any media-type" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -281,7 +262,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain seatNonBid for the called bidder" assert response.ext.prebid.modules.errors.pbOrtb2Blocking["${PB_ORTB2_BLOCKING.code}-${BIDDER_REQUEST.value}-hook"].first @@ -314,7 +295,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain seatNonBid for the called bidder" assert response.ext.prebid.modules.errors.pbOrtb2Blocking["${PB_ORTB2_BLOCKING.code}-${BIDDER_REQUEST.value}-hook"].first @@ -356,7 +337,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response shouldn't contain any seatbid" assert !response.seatbid @@ -396,7 +377,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only allowed seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -462,7 +443,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only allowed seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -500,7 +481,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain proper seatbid" assert getOrtb2Attributes(response.seatbid.first.bid.first, attributeName) == [ortb2Attributes]*.toString() @@ -547,7 +528,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only allowed seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -578,7 +559,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only allowed seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -621,7 +602,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only allowed seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -652,7 +633,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only allowed seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -688,7 +669,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only allowed seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -729,7 +710,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response shouldn't contain any seatbid" assert !response.seatbid.bid.flatten().size() @@ -773,7 +754,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only openx seatbid" assert response.seatbid.size() == 1 @@ -821,7 +802,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only banner seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -871,7 +852,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain banner seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -925,7 +906,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response shouldn't contain any seatbid" assert !response.seatbid.bid.flatten().size() @@ -968,7 +949,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only seatbid with proper deal id" assert response.seatbid.bid.flatten().size() == 1 @@ -1017,7 +998,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request should override blocked ortb2 attribute" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -1060,7 +1041,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request should override blocked ortb2 attribute" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -1109,7 +1090,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only ix seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -1146,7 +1127,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain banner seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -1185,7 +1166,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only ix seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -1220,7 +1201,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain banner seatbid" assert response.seatbid.bid.flatten().size() == 1 @@ -1255,7 +1236,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only seatbid with proper deal id" assert response.seatbid.bid.flatten().size() == 1 @@ -1298,7 +1279,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request should override blocked ortb2 attribute" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -1348,7 +1329,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request should override blocked ortb2 attribute" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -1391,7 +1372,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request should override blocked ortb2 attribute" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -1436,7 +1417,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain only seatbid with proper deal id" assert response.seatbid.bid.flatten().size() == 1 @@ -1472,7 +1453,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS request should contain original ortb2 attribute" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -1514,7 +1495,7 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes the auction request" - def response = pbsServiceWithEnabledOrtb2Blocking.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS response should contain seatNonBid for the called bidder" assert response.ext.seatnonbid.size() == 1 @@ -1525,17 +1506,20 @@ class PbOrtb2BlockingSpec extends ModuleBaseSpec { assert seatNonBid.nonBid[0].statusCode == RESPONSE_REJECTED_ADVERTISER_BLOCKED } - private static Account getAccountWithOrtb2BlockingConfig(String accountId, Object ortb2Attributes, Ortb2BlockingAttribute attributeName) { + private static Account getAccountWithOrtb2BlockingConfig(String accountId, + Object ortb2Attributes, + Ortb2BlockingAttribute attributeName) { + getAccountWithOrtb2BlockingConfig(accountId, [(attributeName): Ortb2BlockingAttributeConfig.getDefaultConfig(ortb2Attributes, attributeName)]) } - private static Account getAccountWithOrtb2BlockingConfig(String accountId, Map attributes) { - def blockingConfig = new Ortb2BlockingConfig(attributes: attributes) - def executionPlan = ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, PB_ORTB2_BLOCKING, [BIDDER_REQUEST, RAW_BIDDER_RESPONSE]) - def moduleConfig = new PbsModulesConfig(pbOrtb2Blocking: blockingConfig) - def accountHooksConfig = new AccountHooksConfiguration(executionPlan: executionPlan, modules: moduleConfig) - def accountConfig = new AccountConfig(hooks: accountHooksConfig) - new Account(uuid: accountId, config: accountConfig) + private static Account getAccountWithOrtb2BlockingConfig(String accountId, + Map attributes) { + + getAccountWithModuleConfig(accountId, [(BIDDER_REQUEST) : [PB_ORTB2_BLOCKING], (RAW_BIDDER_RESPONSE) : [PB_ORTB2_BLOCKING]]).tap { + it.config.hooks.modules.pbOrtb2Blocking = new Ortb2BlockingConfig(attributes: attributes) + } } private static BidRequest getBidRequestForOrtbAttribute(Ortb2BlockingAttribute attribute, List attributeValue = null) { diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbrequestcorrection/PbRequestCorrectionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbrequestcorrection/PbRequestCorrectionSpec.groovy index d64b5cd2637..1771943ee1f 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbrequestcorrection/PbRequestCorrectionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbrequestcorrection/PbRequestCorrectionSpec.groovy @@ -4,6 +4,7 @@ import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AccountHooksConfiguration import org.prebid.server.functional.model.config.PbRequestCorrectionConfig import org.prebid.server.functional.model.config.PbsModulesConfig +import org.prebid.server.functional.model.config.Stage import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.AppExt @@ -15,6 +16,8 @@ import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.tests.module.ModuleBaseSpec import org.prebid.server.functional.util.PBSUtils +import static org.prebid.server.functional.model.config.ModuleName.PB_REQUEST_CORRECTION +import static org.prebid.server.functional.model.config.Stage.PROCESSED_AUCTION_REQUEST import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP import static org.prebid.server.functional.model.request.auction.OperationState.YES @@ -27,12 +30,6 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { private static final String ANDROID = "android" private static final String IOS = "IOS" - private static final PrebidServerService pbsServiceWithRequestCorrectionModule = pbsServiceFactory.getService(getRequestCorrectionSettings()) - - def cleanupSpec() { - pbsServiceFactory.removeContainer(getRequestCorrectionSettings()) - } - def "PBS should remove positive instl from imps for android app when request correction is enabled for account"() { given: "Android APP bid request with version lover then version threshold" def prebid = new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD) @@ -47,7 +44,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request shouldn't contain imp.instl" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -80,7 +77,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain original imp.instl" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -108,7 +105,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain original imp.instl" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -138,7 +135,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain original imp.instl" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -167,7 +164,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain original imp.instl" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -189,7 +186,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain original imp.instl" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -211,7 +208,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain original imp.instl" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -241,7 +238,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain original imp.instl" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -261,7 +258,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request shouldn't contain device.ua" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -289,7 +286,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain device.ua" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -319,7 +316,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain device.ua" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -348,7 +345,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain device.ua" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -377,7 +374,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain device.ua" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -398,7 +395,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain device.ua" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -419,7 +416,7 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain device.ua" def bidderRequest = bidder.getBidderRequest(bidRequest.id) @@ -441,18 +438,16 @@ class PbRequestCorrectionSpec extends ModuleBaseSpec { accountDao.save(account) when: "PBS processes auction request" - pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bidder request should contain request device ua" def bidderRequest = bidder.getBidderRequest(bidRequest.id) assert bidderRequest.device.ua == deviceUa } - private static Account createAccountWithRequestCorrectionConfig(BidRequest bidRequest, - PbRequestCorrectionConfig requestCorrectionConfig) { - def pbsModulesConfig = new PbsModulesConfig(pbRequestCorrection: requestCorrectionConfig) - def accountHooksConfig = new AccountHooksConfiguration(modules: pbsModulesConfig) - def accountConfig = new AccountConfig(hooks: accountHooksConfig) - new Account(uuid: bidRequest.accountId, config: accountConfig) + private static Account createAccountWithRequestCorrectionConfig(BidRequest bidRequest, PbRequestCorrectionConfig requestCorrectionConfig) { + getAccountWithModuleConfig(bidRequest.accountId, [(PROCESSED_AUCTION_REQUEST): [PB_REQUEST_CORRECTION]]).tap { + it.config.hooks.modules.pbRequestCorrection = requestCorrectionConfig + } } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbresponsecorrenction/PbResponseCorrectionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbresponsecorrenction/PbResponseCorrectionSpec.groovy index fb7ca93eb9f..b9743e29c19 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbresponsecorrenction/PbResponseCorrectionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbresponsecorrenction/PbResponseCorrectionSpec.groovy @@ -2,11 +2,8 @@ package org.prebid.server.functional.tests.module.pbresponsecorrenction import org.prebid.server.functional.model.config.AccountAuctionConfig import org.prebid.server.functional.model.config.AccountCacheConfig -import org.prebid.server.functional.model.config.AccountConfig -import org.prebid.server.functional.model.config.AccountHooksConfiguration import org.prebid.server.functional.model.config.AppVideoHtml import org.prebid.server.functional.model.config.PbResponseCorrection -import org.prebid.server.functional.model.config.PbsModulesConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Imp @@ -15,13 +12,14 @@ import org.prebid.server.functional.model.response.auction.BidExt import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.Meta import org.prebid.server.functional.model.response.auction.Prebid -import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.tests.module.ModuleBaseSpec import org.prebid.server.functional.util.PBSUtils import java.time.Instant import static org.prebid.server.functional.model.bidder.BidderName.GENERIC +import static org.prebid.server.functional.model.config.ModuleName.PB_RESPONSE_CORRECTION +import static org.prebid.server.functional.model.config.Stage.ALL_PROCESSED_BID_RESPONSES import static org.prebid.server.functional.model.request.auction.BidRequest.getDefaultBidRequest import static org.prebid.server.functional.model.request.auction.BidRequest.getDefaultVideoRequest import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP @@ -35,15 +33,6 @@ import static org.prebid.server.functional.model.response.auction.MediaType.VIDE class PbResponseCorrectionSpec extends ModuleBaseSpec { private final static int OPTIMAL_MAX_LENGTH = 20 - private static final Map PBS_CONFIG = ["adapter-defaults.modifying-vast-xml-allowed": "false", - "adapters.generic.modifying-vast-xml-allowed": "false"] + - getResponseCorrectionConfig() - - private static final PrebidServerService pbsServiceWithResponseCorrectionModule = pbsServiceFactory.getService(PBS_CONFIG) - - def cleanupSpec() { - pbsServiceFactory.removeContainer(PBS_CONFIG) - } def "PBS shouldn't modify response when in account correction module disabled"() { given: "Start up time" @@ -59,14 +48,16 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { bidder.setResponse(bidRequest.id, bidResponse) and: "Save account with enabled response correction module" - def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest, responseCorrectionEnabled, appVideoHtmlEnabled) + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest, + responseCorrectionEnabled, + appVideoHtmlEnabled) accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS shouldn't emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) assert getLogsByText(logsByTime, bidResponse.seatbid[0].bid[0].id).size() == 0 and: "Response should contain seatBid" @@ -106,10 +97,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS shouldn't emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) assert getLogsByText(logsByTime, bidResponse.seatbid[0].bid[0].id).size() == 0 and: "Response should contain seatBid" @@ -148,10 +139,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS shouldn't emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) assert getLogsByText(logsByTime, bidResponse.seatbid[0].bid[0].id).size() == 0 and: "Response should contain seatBid" @@ -183,10 +174,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) def bidId = bidResponse.seatbid[0].bid[0].id def responseCorrection = getLogsByText(logsByTime, bidId) assert responseCorrection[0].contains("Bid $bidId of bidder generic has an JSON ADM, that appears to be native" as String) @@ -222,10 +213,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS shouldn't emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) assert getLogsByText(logsByTime, bidResponse.seatbid[0].bid[0].id).size() == 0 and: "Response should contain seatBid" @@ -265,10 +256,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) def bidId = bidResponse.seatbid[0].bid[0].id def responseCorrection = getLogsByText(logsByTime, bidId) assert responseCorrection[0].contains("Bid $bidId of bidder generic has an JSON ADM, that appears to be native" as String) @@ -306,10 +297,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS shouldn't emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) assert getLogsByText(logsByTime, bidResponse.seatbid[0].bid[0].id).size() == 0 and: "Response should contain seatBid" @@ -343,10 +334,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS shouldn't emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) assert getLogsByText(logsByTime, bidResponse.seatbid[0].bid[0].id).size() == 0 and: "Response should contain seatBid" @@ -390,10 +381,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) def bidId = bidResponse.seatbid[0].bid[0].id def responseCorrection = getLogsByText(logsByTime, bidId) assert responseCorrection.size() == 1 @@ -445,10 +436,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) def bidId = bidResponse.seatbid[0].bid[0].id def responseCorrection = getLogsByText(logsByTime, bidId) assert responseCorrection.size() == 1 @@ -500,10 +491,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) def bidId = bidResponse.seatbid[0].bid[0].id def responseCorrection = getLogsByText(logsByTime, bidId) assert responseCorrection.size() == 1 @@ -548,10 +539,10 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should emit log" - def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) def bidId = bidResponse.seatbid[0].bid[0].id def responseCorrection = getLogsByText(logsByTime, bidId) assert responseCorrection.size() == 2 @@ -595,11 +586,11 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { accountDao.save(accountWithResponseCorrectionModule) when: "PBS processes auction request" - def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBS should emit log" def responseCorrectionLog = "Bid ${bidResponse.seatbid[0].bid[0].id} of bidder generic: changing media type to banner" - assert pbsServiceWithResponseCorrectionModule.isContainLogsByValue(responseCorrectionLog) + assert pbsServiceWithMultipleModules.isContainLogsByValue(responseCorrectionLog) and: "Response should contain seatBid" assert response.seatbid.size() == 1 @@ -625,10 +616,13 @@ class PbResponseCorrectionSpec extends ModuleBaseSpec { ] } - private static Account accountConfigWithResponseCorrectionModule(BidRequest bidRequest, Boolean enabledResponseCorrection = true, Boolean enabledAppVideoHtml = true) { - def modulesConfig = new PbsModulesConfig(pbResponseCorrection: new PbResponseCorrection( - enabled: enabledResponseCorrection, appVideoHtml: new AppVideoHtml(enabled: enabledAppVideoHtml))) - def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: modulesConfig)) - new Account(uuid: bidRequest.getAccountId(), config: accountConfig) + private static Account accountConfigWithResponseCorrectionModule(BidRequest bidRequest, + Boolean enabledResponseCorrection = true, + Boolean enabledAppVideoHtml = true) { + + getAccountWithModuleConfig(bidRequest.accountId, [(ALL_PROCESSED_BID_RESPONSES): [PB_RESPONSE_CORRECTION]]).tap { + it.config.hooks.modules.pbResponseCorrection = new PbResponseCorrection( + enabled: enabledResponseCorrection, appVideoHtml: new AppVideoHtml(enabled: enabledAppVideoHtml)) + } } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbrichmedia/PbRichMediaFilterSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbrichmedia/PbRichMediaFilterSpec.groovy index 037a38fb922..42da9f9b976 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbrichmedia/PbRichMediaFilterSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbrichmedia/PbRichMediaFilterSpec.groovy @@ -13,6 +13,7 @@ import org.prebid.server.functional.model.request.auction.StoredBidResponse import org.prebid.server.functional.model.response.auction.AnalyticResult import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.tests.module.ModuleBaseSpec import org.prebid.server.functional.util.PBSUtils @@ -27,16 +28,22 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { private static final String PATTERN_NAME = PBSUtils.randomString private static final String PATTERN_NAME_ACCOUNT = PBSUtils.randomString - private static final Map DISABLED_FILTER_SPECIFIC_PATTERN_NAME_CONFIG = getRichMediaFilterSettings(PATTERN_NAME, false) - private static final Map SPECIFIC_PATTERN_NAME_CONFIG = getRichMediaFilterSettings(PATTERN_NAME) - private static final Map SNAKE_SPECIFIC_PATTERN_NAME_CONFIG = (getRichMediaFilterSettings(PATTERN_NAME) + + private static final PbsContainerConfig DISABLED_FILTER_SPECIFIC_PATTERN_NAME_CONFIG = getRichMediaFilterSettings(PATTERN_NAME, false) + private static final PbsContainerConfig SPECIFIC_PATTERN_NAME_CONFIG = getRichMediaFilterSettings(PATTERN_NAME) + private static final PbsContainerConfig SNAKE_SPECIFIC_PATTERN_NAME_CONFIG = getRichMediaFilterSettings(PATTERN_NAME) + ["hooks.host-execution-plan": encode(ExecutionPlan.getSingleEndpointExecutionPlan(AUCTION, PB_RICHMEDIA_FILTER, [ALL_PROCESSED_BID_RESPONSES]).tap { endpoints.values().first().stages.values().first().groups.first.hookSequenceSnakeCase = [new HookId(moduleCodeSnakeCase: PB_RICHMEDIA_FILTER.code, hookImplCodeSnakeCase: "${PB_RICHMEDIA_FILTER.code}-${ALL_PROCESSED_BID_RESPONSES.value}-hook")] - })]).collectEntries { key, value -> [(key.toString()): value.toString()] } + })] - private static final PrebidServerService pbsServiceWithDisabledMediaFilter = pbsServiceFactory.getService(DISABLED_FILTER_SPECIFIC_PATTERN_NAME_CONFIG) - private static final PrebidServerService pbsServiceWithEnabledMediaFilter = pbsServiceFactory.getService(SPECIFIC_PATTERN_NAME_CONFIG) - private static final PrebidServerService pbsServiceWithEnabledMediaFilterAndDifferentCaseStrategy = pbsServiceFactory.getService(SNAKE_SPECIFIC_PATTERN_NAME_CONFIG) + private static PrebidServerService pbsServiceWithDisabledMediaFilter + private static PrebidServerService pbsServiceWithEnabledMediaFilter + private static PrebidServerService pbsServiceWithEnabledMediaFilterAndDifferentCaseStrategy + + def setupSpec() { + pbsServiceWithDisabledMediaFilter = pbsServiceFactory.getService(DISABLED_FILTER_SPECIFIC_PATTERN_NAME_CONFIG) + pbsServiceWithEnabledMediaFilter = pbsServiceFactory.getService(SPECIFIC_PATTERN_NAME_CONFIG) + pbsServiceWithEnabledMediaFilterAndDifferentCaseStrategy = pbsServiceFactory.getService(SNAKE_SPECIFIC_PATTERN_NAME_CONFIG) + } def cleanupSpec() { pbsServiceFactory.removeContainer(DISABLED_FILTER_SPECIFIC_PATTERN_NAME_CONFIG) @@ -45,10 +52,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { } def "PBS should process request without rich media module when host config have empty settings"() { - given: "Prebid server with empty settings for module" - def prebidServerService = pbsServiceFactory.getService(pbsConfig) - - and: "BidRequest with stored response" + given: "BidRequest with stored response" def storedResponseId = PBSUtils.randomNumber def bidRequest = BidRequest.defaultBidRequest.tap { ext.prebid.returnAllBidStatus = true @@ -63,12 +67,12 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { def storedResponse = new StoredResponse(responseId: storedResponseId, storedBidResponse: storedBidResponse) storedResponseDao.save(storedResponse) - and: "Account in the DB" - def account = new Account(uuid: bidRequest.getAccountId()) + and: "Account with enabled richMedia config in the DB" + def account = getAccountWithRichmediaFilter(bidRequest.accountId, filterMraid, mraidScriptPattern) accountDao.save(account) when: "PBS processes auction request" - def response = prebidServerService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Response header should contain seatbid" assert response.seatbid.size() == 1 @@ -79,14 +83,12 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { and: "Response shouldn't contain analytics" assert !getAnalyticResults(response) - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - where: - pbsConfig << [getRichMediaFilterSettings(PBSUtils.randomString, null), - getRichMediaFilterSettings(null, true), - getRichMediaFilterSettings(null, false), - getRichMediaFilterSettings(null, null)] + filterMraid | mraidScriptPattern + true | PBSUtils.randomString + true | null + false | null + null | null } def "PBS should process request without analytics when adm matches with pattern name and filter set to disabled in host config"() { @@ -106,7 +108,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { storedResponseDao.save(storedResponse) and: "Account in the DB" - def account = new Account(uuid: bidRequest.getAccountId()) + def account = new Account(uuid: bidRequest.accountId) accountDao.save(account) when: "PBS processes auction request" @@ -125,7 +127,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { admValue << [PATTERN_NAME, "${PBSUtils.randomString}-${PATTERN_NAME}", "${PATTERN_NAME}-${PBSUtils.randomString}"] } - def "PBS should reject request with error and provide analytic when adm matches with pattern name and filter set to enabled in host config"() { + def "PBS should reject request with error and provide analytic when adm matches with pattern name and filter set to enabled in config"() { given: "BidRequest with stored response" def storedResponseId = PBSUtils.randomNumber def bidRequest = BidRequest.defaultBidRequest.tap { @@ -142,7 +144,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { storedResponseDao.save(storedResponse) and: "Account in the DB" - def account = new Account(uuid: bidRequest.getAccountId()) + def account = getAccountWithRichmediaFilter(bidRequest.accountId, true, PATTERN_NAME) accountDao.save(account) when: "PBS processes auction request" @@ -169,7 +171,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { admValue << [PATTERN_NAME, "${PBSUtils.randomString}-${PATTERN_NAME}", "${PATTERN_NAME}.${PBSUtils.randomString}"] } - def "PBS should process request without analytics when adm is #admValue and filter enabled in host config"() { + def "PBS should process request without analytics when adm is #admValue and filter enabled in config"() { given: "BidRequest with stored response" def storedResponseId = PBSUtils.randomNumber def bidRequest = BidRequest.defaultBidRequest.tap { @@ -186,9 +188,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { storedResponseDao.save(storedResponse) and: "Account with enabled richMedia config in the DB" - def richMediaFilterConfig = new PbsModulesConfig(pbRichmediaFilter: new RichmediaFilter(filterMraid: true)) - def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: richMediaFilterConfig)) - def account = new Account(uuid: bidRequest.getAccountId(), config: accountConfig) + def account = getAccountWithRichmediaFilter(bidRequest.accountId, true, null) accountDao.save(account) when: "PBS processes auction request" @@ -217,9 +217,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { } and: "Account with enabled richMedia config in the DB" - def richMediaFilterConfig = new PbsModulesConfig(pbRichmediaFilter: new RichmediaFilter(filterMraid: true, mraidScriptPattern: PATTERN_NAME)) - def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: richMediaFilterConfig)) - def account = new Account(uuid: bidRequest.getAccountId(), config: accountConfig) + def account = getAccountWithRichmediaFilter(bidRequest.accountId, true, PATTERN_NAME) accountDao.save(account) and: "Stored bid response in DB" @@ -263,9 +261,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { } and: "Account with disabled richMedia config in the DB" - def richMediaFilterConfig = new PbsModulesConfig(pbRichmediaFilter: new RichmediaFilter(filterMraid: false, mraidScriptPattern: PATTERN_NAME)) - def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: richMediaFilterConfig)) - def account = new Account(uuid: bidRequest.getAccountId(), config: accountConfig) + def account = getAccountWithRichmediaFilter(bidRequest.accountId, false, PATTERN_NAME) accountDao.save(account) and: "Stored bid response in DB" @@ -301,9 +297,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { } and: "Account with enabled richMedia config in the DB" - def richMediaFilterConfig = new PbsModulesConfig(pbRichmediaFilter: new RichmediaFilter(filterMraid: true, mraidScriptPattern: PATTERN_NAME_ACCOUNT)) - def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: richMediaFilterConfig)) - def account = new Account(uuid: bidRequest.getAccountId(), config: accountConfig) + def account = getAccountWithRichmediaFilter(bidRequest.accountId, true, PATTERN_NAME_ACCOUNT) accountDao.save(account) and: "Stored bid response in DB" @@ -344,9 +338,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { } and: "Account with enabled richMedia config in the DB" - def richMediaFilterConfig = new PbsModulesConfig(pbRichmediaFilter: new RichmediaFilter(filterMraid: true, mraidScriptPattern: PATTERN_NAME_ACCOUNT)) - def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: richMediaFilterConfig)) - def account = new Account(uuid: bidRequest.getAccountId(), config: accountConfig) + def account = getAccountWithRichmediaFilter(bidRequest.accountId, true, PATTERN_NAME_ACCOUNT) accountDao.save(account) and: "Stored bid response in DB" @@ -371,7 +363,10 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { def "PBS should process any request without analytics and errors when pb-richmedia-filter hook is disabled"() { given: "PBS with disabled pb-richmedia-filter hook" - def pbsServiceWithDisabledMediaFilterHook = pbsServiceFactory.getService(getDisabledRichMediaFilterSettings(PATTERN_NAME)) + def pbsConfig = getRichMediaFilterSettings(PATTERN_NAME) + + getModuleBaseSettings(PB_RICHMEDIA_FILTER, false) + + ["hooks.host-execution-plan": null] + def pbsServiceWithDisabledMediaFilterHook = pbsServiceFactory.getService(pbsConfig) and: "BidRequest with stored response" def storedResponseId = PBSUtils.randomNumber @@ -384,7 +379,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { and: "Account with enabled richMedia config in the DB" def richMediaFilterConfig = new PbsModulesConfig(pbRichmediaFilter: new RichmediaFilter(filterMraid: true, mraidScriptPattern: PATTERN_NAME_ACCOUNT)) def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: richMediaFilterConfig)) - def account = new Account(uuid: bidRequest.getAccountId(), config: accountConfig) + def account = new Account(uuid: bidRequest.accountId, config: accountConfig) accountDao.save(account) and: "Stored bid response in DB" @@ -427,7 +422,7 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { storedResponseDao.save(storedResponse) and: "Account in the DB" - def account = new Account(uuid: bidRequest.getAccountId()) + def account = new Account(uuid: bidRequest.accountId) accountDao.save(account) when: "PBS processes auction request" @@ -453,4 +448,12 @@ class PbRichMediaFilterSpec extends ModuleBaseSpec { where: admValue << [PATTERN_NAME, "${PBSUtils.randomString}-${PATTERN_NAME}", "${PATTERN_NAME}.${PBSUtils.randomString}"] } + + private static Account getAccountWithRichmediaFilter(String accountId, + Boolean filterMraid, + String mraidScriptPattern) { + getAccountWithModuleConfig(accountId, [(ALL_PROCESSED_BID_RESPONSES): [PB_RICHMEDIA_FILTER]]).tap { + it.config.hooks.modules.pbRichmediaFilter = new RichmediaFilter(filterMraid: filterMraid, mraidScriptPattern: mraidScriptPattern) + } + } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineAliasSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineAliasSpec.groovy index 9eb712715d5..92e2a7e47c5 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineAliasSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineAliasSpec.groovy @@ -11,7 +11,7 @@ import static org.prebid.server.functional.model.bidder.BidderName.OPENX_ALIAS import static org.prebid.server.functional.model.config.PbRulesEngine.createRulesEngineWithRule import static org.prebid.server.functional.model.config.RuleEngineModelRuleResult.createRuleEngineModelRuleWithExcludeResult import static org.prebid.server.functional.model.config.RuleEngineModelRuleResult.createRuleEngineModelRuleWithIncludeResult -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.response.auction.BidRejectionReason.REQUEST_BIDDER_REMOVED_BY_RULE_ENGINE_MODULE class PbRuleEngineAliasSpec extends PbRuleEngineBaseSpec { @@ -35,7 +35,7 @@ class PbRuleEngineAliasSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.size() == 1 @@ -97,7 +97,7 @@ class PbRuleEngineAliasSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -157,7 +157,7 @@ class PbRuleEngineAliasSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seat" assert bidResponse.seatbid.seat == [ALIAS] @@ -219,7 +219,7 @@ class PbRuleEngineAliasSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineBaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineBaseSpec.groovy index 494a44f8460..6d9a5fe544c 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineBaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineBaseSpec.groovy @@ -5,8 +5,10 @@ import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.bidder.Openx import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AccountHooksConfiguration +import org.prebid.server.functional.model.config.ModuleName import org.prebid.server.functional.model.config.PbRulesEngine import org.prebid.server.functional.model.config.PbsModulesConfig +import org.prebid.server.functional.model.config.Stage import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.pricefloors.Country import org.prebid.server.functional.model.request.auction.Amx @@ -41,16 +43,13 @@ import static org.prebid.server.functional.util.privacy.TcfConsent.GENERIC_VENDO abstract class PbRuleEngineBaseSpec extends ModuleBaseSpec { protected static final List MULTI_BID_ADAPTERS = [GENERIC, OPENX, AMX].sort() - protected static final Integer OPENX_VENDOR_ID = PBSUtils.getRandomNumber(0, 65534) - protected static final Integer AMX_VENDOR_ID = PBSUtils.getRandomNumber(0, 65534) - protected static final String APPLIED_FOR_ALL_IMPS = "*" protected static final String DEFAULT_CONDITIONS = "default" + protected final static Closure INVALID_CONFIGURATION_FOR_STRINGS_LOG_WARNING = { accountId, functionType -> "Failed to parse rule-engine config for account $accountId: " + "Function '$functionType' configuration is invalid: " + "Field '$functionType.fieldName' is required and has to be an array of strings" } - protected final static Closure INVALID_CONFIGURATION_FOR_SINGLE_STRING_LOG_WARNING = { accountId, functionType -> "Failed to parse rule-engine config for account $accountId: " + "Function '$functionType' configuration is invalid: " + @@ -69,25 +68,6 @@ abstract class PbRuleEngineBaseSpec extends ModuleBaseSpec { "Field '$functionType.fieldName' is required and has to be an array of integers" } - protected static final Map ENABLED_DEBUG_LOG_MODE = ["logging.level.root": "debug"] - protected static final Map OPENX_CONFIG = ["adapters.${OPENX}.enabled" : "true", - "adapters.${OPENX}.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "adapters.${OPENX}.meta-info.vendor-id": OPENX_VENDOR_ID as String] - protected static final Map AMX_CONFIG = ["adapters.${AMX}.enabled" : "true", - "adapters.${AMX}.endpoint" : "$networkServiceContainer.rootUri/auction".toString(), - "adapters.${AMX}.meta-info.vendor-id": AMX_VENDOR_ID as String] - protected static final Map OPENX_ALIAS_CONFIG = ["adapters.${OPENX}.aliases.${OPENX_ALIAS}.enabled" : "true", - "adapters.${OPENX}.aliases.${OPENX_ALIAS}.meta-info.vendor-id": "0", - "adapters.${OPENX}.aliases.${OPENX_ALIAS}.endpoint" : "$networkServiceContainer.rootUri/auction".toString()] - protected static final String CONFIG_DATA_CENTER = PBSUtils.randomString - private static final String USER_SYNC_URL = "$networkServiceContainer.rootUri/generic-usersync" - private static final Map GENERIC_CONFIG = [ - "adapters.${GENERIC.value}.usersync.redirect.url" : USER_SYNC_URL, - "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String] - protected static final PrebidServerService pbsServiceWithRulesEngineModule = pbsServiceFactory.getService(GENERIC_CONFIG + - getRulesEngineSettings() + AMX_CONFIG + OPENX_CONFIG + OPENX_ALIAS_CONFIG + ['datacenter-region': CONFIG_DATA_CENTER] + - ENABLED_DEBUG_LOG_MODE) - protected static BidRequest getDefaultBidRequestWithMultiplyBidders(DistributionChannel distributionChannel = SITE) { BidRequest.getDefaultBidRequest(distributionChannel).tap { it.imp[0].ext.prebid.bidder.amx = new Amx() @@ -114,8 +94,10 @@ abstract class PbRuleEngineBaseSpec extends ModuleBaseSpec { } protected static Account getAccountWithRulesEngine(String accountId, PbRulesEngine ruleEngine) { - def accountHooksConfiguration = new AccountHooksConfiguration(modules: new PbsModulesConfig(pbRuleEngine: ruleEngine)) - new Account(uuid: accountId, config: new AccountConfig(hooks: accountHooksConfiguration)) + + getAccountWithModuleConfig(accountId, [(Stage.PROCESSED_AUCTION_REQUEST) : [ModuleName.PB_RULE_ENGINE]]).tap { + it.config.hooks.modules.pbRuleEngine = ruleEngine + } } protected static BidRequest createBidRequestWithDomains(DistributionChannel type, String domain, boolean usePublisher = true) { @@ -178,15 +160,15 @@ abstract class PbRuleEngineBaseSpec extends ModuleBaseSpec { protected static waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) { PBSUtils.waitUntil({ - pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) - pbsServiceWithRulesEngineModule.isContainLogsByValue("Successfully parsed rule-engine config for account $bidRequest.accountId") + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.isContainLogsByValue("Successfully parsed rule-engine config for account $bidRequest.accountId") }) } protected static waitUntilFailedParsedAndCacheAccount(bidRequest) { PBSUtils.waitUntil({ - pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) - pbsServiceWithRulesEngineModule.isContainLogsByValue("Failed to parse rule-engine config for account $bidRequest.accountId") + pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) + pbsServiceWithMultipleModules.isContainLogsByValue("Failed to parse rule-engine config for account $bidRequest.accountId") }) } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineContextSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineContextSpec.groovy index 02820762c87..e37e85dbeb9 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineContextSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineContextSpec.groovy @@ -33,7 +33,7 @@ import static org.prebid.server.functional.model.pricefloors.MediaType.BANNER import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP import static org.prebid.server.functional.model.request.auction.DistributionChannel.DOOH import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.request.auction.ImpUnitCode.GPID import static org.prebid.server.functional.model.request.auction.ImpUnitCode.PB_AD_SLOT import static org.prebid.server.functional.model.request.auction.ImpUnitCode.STORED_REQUEST @@ -62,7 +62,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -122,7 +122,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -164,7 +164,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -229,7 +229,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -274,7 +274,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -293,7 +293,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_STRINGS_LOG_WARNING(bidRequest.accountId, DOMAIN_IN)) where: @@ -339,7 +339,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -405,7 +405,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -468,7 +468,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -530,7 +530,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -574,7 +574,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -593,7 +593,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { assert !bidResponse.ext?.errors then: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_STRINGS_LOG_WARNING(bidRequest.accountId, BUNDLE_IN)) } @@ -620,7 +620,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -682,7 +682,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -724,7 +724,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -743,7 +743,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) then: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_STRINGS_LOG_WARNING(bidRequest.accountId, MEDIA_TYPE_IN)) where: @@ -774,7 +774,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -834,7 +834,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -882,7 +882,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -953,7 +953,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -1006,7 +1006,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -1025,7 +1025,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_STRINGS_LOG_WARNING(bidRequest.accountId, AD_UNIT_CODE_IN)) where: @@ -1062,7 +1062,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -1125,7 +1125,7 @@ class PbRuleEngineContextSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineCoreSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineCoreSpec.groovy index ab986d3bc3a..c98acddd9a6 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineCoreSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineCoreSpec.groovy @@ -21,7 +21,7 @@ import static org.prebid.server.functional.model.config.RuleEngineModelRuleResul import static org.prebid.server.functional.model.config.RuleEngineModelRuleResult.createRuleEngineModelRuleWithLogATagResult import static org.prebid.server.functional.model.config.Stage.PROCESSED_AUCTION_REQUEST import static org.prebid.server.functional.model.pricefloors.Country.BULGARIA -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.request.auction.TraceLevel.VERBOSE import static org.prebid.server.functional.model.response.auction.BidRejectionReason.ERROR_NO_BID import static org.prebid.server.functional.model.response.auction.BidRejectionReason.REQUEST_BIDDER_REMOVED_BY_RULE_ENGINE_MODULE @@ -45,10 +45,10 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) and: "Flush metric" - flushMetrics(pbsServiceWithRulesEngineModule) + flushMetrics(pbsServiceWithMultipleModules) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Response should contain seat bid" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -64,7 +64,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { assert !bidResponse.ext?.errors and: "PBs should populate call and update metrics" - def metrics = pbsServiceWithRulesEngineModule.sendCollectedMetricsRequest() + def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() assert metrics[CALL_METRIC(PB_RULE_ENGINE, PROCESSED_AUCTION_REQUEST)] == 1 assert metrics[UPDATE_METRIC(PB_RULE_ENGINE, PROCESSED_AUCTION_REQUEST)] == 1 @@ -95,7 +95,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [OPENX, AMX].sort() @@ -159,7 +159,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [OPENX, AMX].sort() @@ -212,7 +212,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.size() == 0 @@ -245,7 +245,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -278,7 +278,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat == [OPENX] @@ -338,7 +338,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seatBids" assert bidResponse.seatbid.seat.sort() == [OPENX, AMX].sort() @@ -397,7 +397,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat == [GENERIC] @@ -455,7 +455,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -487,7 +487,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { it.values.resultFunction == groups.rules.first.results.first.function.value it.values.conditionFired == groups.rules.first.conditions.first - it.appliedTo.impIds == [APPLIED_FOR_ALL_IMPS] + it.appliedTo.impIds == [WILDCARD] } verifyAll(impResult) { @@ -514,7 +514,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Response should contain seat bid" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -578,7 +578,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Response should contain seat bid" assert bidResponse.seatbid.seat.sort() == [GENERIC, OPENX].sort() @@ -646,7 +646,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [OPENX, AMX].sort() @@ -706,7 +706,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -766,7 +766,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -797,7 +797,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { it.values.analyticsValue == analyticsValue it.values.resultFunction == LOG_A_TAG.value it.values.conditionFired == DEFAULT_CONDITIONS - it.appliedTo.impIds == [APPLIED_FOR_ALL_IMPS] + it.appliedTo.impIds == [WILDCARD] } and: "Analytics imp result shouldn't contain remove info" @@ -826,7 +826,7 @@ class PbRuleEngineCoreSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain two seat" assert bidResponse.seatbid.size() == 2 diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineDeviceSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineDeviceSpec.groovy index fabcab27548..8efcded4339 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineDeviceSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineDeviceSpec.groovy @@ -19,7 +19,7 @@ import static org.prebid.server.functional.model.config.RuleEngineFunction.DEVIC import static org.prebid.server.functional.model.config.RuleEngineFunction.DEVICE_TYPE import static org.prebid.server.functional.model.config.RuleEngineFunction.DEVICE_TYPE_IN import static org.prebid.server.functional.model.pricefloors.Country.USA -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.response.auction.BidRejectionReason.REQUEST_BIDDER_REMOVED_BY_RULE_ENGINE_MODULE class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { @@ -46,7 +46,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -108,7 +108,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -150,7 +150,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -213,7 +213,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -257,7 +257,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -276,7 +276,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_STRINGS_LOG_WARNING(bidRequest.accountId, DEVICE_COUNTRY_IN)) } @@ -305,7 +305,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -324,7 +324,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_INTEGERS_LOG_WARNING(bidRequest.accountId, DEVICE_TYPE_IN)) } @@ -351,7 +351,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -413,7 +413,7 @@ class PbRuleEngineDeviceSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineInfrastructureSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineInfrastructureSpec.groovy index ba125f07a3a..7704726089b 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineInfrastructureSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineInfrastructureSpec.groovy @@ -13,7 +13,7 @@ import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.config.PbRulesEngine.createRulesEngineWithRule import static org.prebid.server.functional.model.config.RuleEngineFunction.DATA_CENTER import static org.prebid.server.functional.model.config.RuleEngineFunction.DATA_CENTER_IN -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.response.auction.BidRejectionReason.REQUEST_BIDDER_REMOVED_BY_RULE_ENGINE_MODULE class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { @@ -29,7 +29,7 @@ class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { def pbRuleEngine = createRulesEngineWithRule().tap { it.ruleSets[0].modelGroups[0].schema[0].tap { it.function = DATA_CENTER_IN - it.args = new RuleEngineFunctionArgs(countries: [CONFIG_DATA_CENTER]) + it.args = new RuleEngineFunctionArgs(countries: [RANDOM_DATACENTER_REGION]) } } @@ -41,7 +41,7 @@ class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -60,7 +60,7 @@ class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_STRINGS_LOG_WARNING(bidRequest.accountId, DATA_CENTER_IN)) } @@ -72,7 +72,7 @@ class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { def pbRuleEngine = createRulesEngineWithRule().tap { it.ruleSets[0].modelGroups[0].schema[0].tap { it.function = DATA_CENTER_IN - it.args = new RuleEngineFunctionArgs(datacenters: [CONFIG_DATA_CENTER]) + it.args = new RuleEngineFunctionArgs(datacenters: [RANDOM_DATACENTER_REGION]) } } @@ -84,7 +84,7 @@ class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -144,7 +144,7 @@ class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -171,7 +171,7 @@ class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { def pbRuleEngine = createRulesEngineWithRule().tap { it.ruleSets[0].modelGroups[0].tap { schema = [new RuleEngineModelSchema(function: DATA_CENTER)] - rules[0].conditions = [CONFIG_DATA_CENTER] + rules[0].conditions = [RANDOM_DATACENTER_REGION] } } @@ -183,7 +183,7 @@ class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -243,7 +243,7 @@ class PbRuleEngineInfrastructureSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEnginePrivacySpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEnginePrivacySpec.groovy index 64106286821..6999b21a802 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEnginePrivacySpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEnginePrivacySpec.groovy @@ -33,7 +33,7 @@ import static org.prebid.server.functional.model.config.RuleEngineFunction.TCF_I import static org.prebid.server.functional.model.config.RuleEngineFunction.USER_FPD_AVAILABLE import static org.prebid.server.functional.model.request.GppSectionId.TCF_EU_V2 import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.response.auction.BidRejectionReason.REQUEST_BIDDER_REMOVED_BY_RULE_ENGINE_MODULE import static org.prebid.server.functional.util.privacy.TcfConsent.GENERIC_VENDOR_ID import static org.prebid.server.functional.util.privacy.TcfConsent.PurposeId.BASIC_ADS @@ -67,7 +67,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -129,7 +129,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -176,7 +176,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -195,7 +195,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_STRINGS_LOG_WARNING(bidRequest.accountId, EID_IN)) } @@ -222,7 +222,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -284,7 +284,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -322,7 +322,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -386,7 +386,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -425,7 +425,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -501,7 +501,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -563,7 +563,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -622,7 +622,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -669,7 +669,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -688,7 +688,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_INTEGERS_LOG_WARNING(bidRequest.accountId, GPP_SID_IN)) } @@ -714,7 +714,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -779,7 +779,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -828,7 +828,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -900,7 +900,7 @@ class PbRuleEnginePrivacySpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineSpecialSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineSpecialSpec.groovy index 8d9a53d13f0..8254c63e6be 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineSpecialSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineSpecialSpec.groovy @@ -12,7 +12,7 @@ import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.config.PbRulesEngine.createRulesEngineWithRule import static org.prebid.server.functional.model.config.RuleEngineFunction.PERCENT import static org.prebid.server.functional.model.config.RuleEngineFunction.PREBID_KEY -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.response.auction.BidRejectionReason.REQUEST_BIDDER_REMOVED_BY_RULE_ENGINE_MODULE class PbRuleEngineSpecialSpec extends PbRuleEngineBaseSpec { @@ -40,7 +40,7 @@ class PbRuleEngineSpecialSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -59,7 +59,7 @@ class PbRuleEngineSpecialSpec extends PbRuleEngineBaseSpec { assert !bidResponse.ext?.errors and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_SINGLE_INTEGER_LOG_WARNING(bidRequest.accountId, PERCENT)) } @@ -83,7 +83,7 @@ class PbRuleEngineSpecialSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -143,7 +143,7 @@ class PbRuleEngineSpecialSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -188,7 +188,7 @@ class PbRuleEngineSpecialSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -207,7 +207,7 @@ class PbRuleEngineSpecialSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, INVALID_CONFIGURATION_FOR_SINGLE_STRING_LOG_WARNING(bidRequest.accountId, PREBID_KEY)) } @@ -236,7 +236,7 @@ class PbRuleEngineSpecialSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [GENERIC, AMX].sort() @@ -300,7 +300,7 @@ class PbRuleEngineSpecialSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineSyncSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineSyncSpec.groovy index 3128e047aae..745d0c1704b 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineSyncSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineSyncSpec.groovy @@ -10,7 +10,7 @@ import static org.prebid.server.functional.model.bidder.BidderName.OPENX import static org.prebid.server.functional.model.config.PbRulesEngine.createRulesEngineWithRule import static org.prebid.server.functional.model.config.RuleEngineModelRuleResult.createRuleEngineModelRuleWithExcludeResult import static org.prebid.server.functional.model.config.RuleEngineModelRuleResult.createRuleEngineModelRuleWithIncludeResult -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.response.auction.BidRejectionReason.REQUEST_BIDDER_REMOVED_BY_RULE_ENGINE_MODULE class PbRuleEngineSyncSpec extends PbRuleEngineBaseSpec { @@ -35,7 +35,7 @@ class PbRuleEngineSyncSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest, cookieHeader) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest, cookieHeader) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == [OPENX, AMX] @@ -92,7 +92,7 @@ class PbRuleEngineSyncSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest, cookieHeader) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest, cookieHeader) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -128,7 +128,7 @@ class PbRuleEngineSyncSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -167,7 +167,7 @@ class PbRuleEngineSyncSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest, cookieHeader) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest, cookieHeader) then: "Bid response shouldn't contain seat" assert bidResponse.seatbid.seat == [GENERIC] @@ -227,7 +227,7 @@ class PbRuleEngineSyncSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest, cookieHeader) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest, cookieHeader) then: "Bid response shouldn't contain seat" assert !bidResponse.seatbid.seat @@ -277,7 +277,7 @@ class PbRuleEngineSyncSpec extends PbRuleEngineBaseSpec { accountDao.save(accountWithRulesEngine) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineValidationSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineValidationSpec.groovy index d43a5114f5d..ce5726a6cb1 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineValidationSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbruleengine/PbRuleEngineValidationSpec.groovy @@ -37,10 +37,10 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) and: "Flush metrics" - flushMetrics(pbsServiceWithRulesEngineModule) + flushMetrics(pbsServiceWithMultipleModules) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -59,7 +59,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "PBs should populate call and noop metrics" - def metrics = pbsServiceWithRulesEngineModule.sendCollectedMetricsRequest() + def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() assert metrics[CALL_METRIC(PB_RULE_ENGINE, PROCESSED_AUCTION_REQUEST)] == 1 assert metrics[NOOP_METRIC(PB_RULE_ENGINE,PROCESSED_AUCTION_REQUEST)] == 1 @@ -91,10 +91,10 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) and: "Flush metrics" - flushMetrics(pbsServiceWithRulesEngineModule) + flushMetrics(pbsServiceWithMultipleModules) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -113,7 +113,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "PBs should populate noop metrics" - def metrics = pbsServiceWithRulesEngineModule.sendCollectedMetricsRequest() + def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() assert metrics[NOOP_METRIC(PB_RULE_ENGINE,PROCESSED_AUCTION_REQUEST)] == 1 } @@ -132,10 +132,10 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) and: "Flush metrics" - flushMetrics(pbsServiceWithRulesEngineModule) + flushMetrics(pbsServiceWithMultipleModules) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -151,7 +151,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS and: "PBs should populate failer metrics" - def metrics = pbsServiceWithRulesEngineModule.sendCollectedMetricsRequest() + def metrics = pbsServiceWithMultipleModules.sendCollectedMetricsRequest() assert metrics[NOOP_METRIC(PB_RULE_ENGINE,PROCESSED_AUCTION_REQUEST)] == 1 } @@ -173,7 +173,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -189,7 +189,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS and: "PBs should emit failed logs" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, "Failed to parse rule-engine config for account $bidRequest.accountId:" + " Weighted list cannot be empty") } @@ -211,7 +211,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -241,7 +241,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { accountDao.save(accountWithRulesEngine) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -280,7 +280,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { waitUntilSuccessfullyParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -314,7 +314,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { accountDao.save(accountWithRulesEngine) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -333,7 +333,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "PBs should emit failed logs" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, "Parsing rule for account $bidRequest.accountId").size() == 1 } @@ -359,7 +359,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "Bid response should contain seats" assert bidResponse.seatbid.seat.sort() == MULTI_BID_ADAPTERS @@ -378,7 +378,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { assert !getAnalyticResults(bidResponse) and: "PBS should emit log" - def logsByTime = pbsServiceWithRulesEngineModule.getLogsByTime(start) + def logsByTime = pbsServiceWithMultipleModules.getLogsByTime(start) assert getLogsByText(logsByTime, "Failed to parse rule-engine config for account $bidRequest.accountId:" + " Weight must be greater than zero") @@ -409,7 +409,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { waitUntilFailedParsedAndCacheAccount(bidRequest) when: "PBS processes auction request" - def bidResponse = pbsServiceWithRulesEngineModule.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithMultipleModules.sendAuctionRequest(bidRequest) then: "PBs should perform bidder request" assert bidder.getBidderRequests(bidRequest.id) @@ -428,7 +428,7 @@ class PbRuleEngineValidationSpec extends PbRuleEngineBaseSpec { assert !bidResponse.ext?.errors and: "Logs should contain error" - def logs = pbsServiceWithRulesEngineModule.getLogsByTime(startTime) + def logs = pbsServiceWithMultipleModules.getLogsByTime(startTime) assert getLogsByText(logs, "Failed to parse rule-engine config for account ${bidRequest.accountId}: " + "Function '${function.value}' configuration is invalid: No arguments allowed") diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsAdjustmentSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsAdjustmentSpec.groovy index 57f368f46a3..a0e44bb5f1e 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsAdjustmentSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsAdjustmentSpec.groovy @@ -27,6 +27,7 @@ import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.MediaType import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.PbsConfig +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.util.CurrencyUtil import org.prebid.server.functional.util.PBSUtils @@ -61,12 +62,12 @@ class PriceFloorsAdjustmentSpec extends PriceFloorsBaseSpec { private static final Integer MAX_STATIC_ADJUST_VALUE = Integer.MAX_VALUE private static final String WILDCARD = '*' - private static final Map PBS_CONFIG = PbsConfig.currencyConverterConfig + + private static final PbsContainerConfig PBS_CONFIG = new PbsContainerConfig(PbsConfig.currencyConverterConfig + FLOORS_CONFIG + GENERIC_ALIAS_CONFIG + ["adapters.openx.enabled" : "true", "adapters.openx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + - ["adapter-defaults.ortb.multiformat-supported": "true"] + ["adapter-defaults.ortb.multiformat-supported": "true"]) private static PrebidServerService pbsService def setupSpec() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsBaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsBaseSpec.groovy index 95ef1318637..6b3c945ab4d 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsBaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsBaseSpec.groovy @@ -14,7 +14,7 @@ import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.BidRequestExt import org.prebid.server.functional.model.request.auction.DistributionChannel import org.prebid.server.functional.model.request.auction.ExtPrebidFloors -import org.prebid.server.functional.model.request.auction.FetchStatus +import org.prebid.server.functional.model.request.auction.AnalyticTagStatus import org.prebid.server.functional.model.request.auction.Prebid import org.prebid.server.functional.model.request.auction.Video import org.prebid.server.functional.service.PrebidServerService @@ -27,7 +27,7 @@ import java.math.RoundingMode import static org.prebid.server.functional.model.request.auction.DebugCondition.ENABLED import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE -import static org.prebid.server.functional.model.request.auction.FetchStatus.INPROGRESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.INPROGRESS import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer abstract class PriceFloorsBaseSpec extends BaseSpec { @@ -136,7 +136,7 @@ abstract class PriceFloorsBaseSpec extends BaseSpec { protected void cacheFloorsProviderRules(BidRequest bidRequest, PrebidServerService pbsService = floorsPbsService, BidderName bidderName = BidderName.GENERIC, - FetchStatus fetchStatus = INPROGRESS) { + AnalyticTagStatus fetchStatus = INPROGRESS) { PBSUtils.waitUntil({ getRequests(pbsService.sendAuctionRequest(bidRequest))[bidderName.value]?.first?.ext?.prebid?.floors?.fetchStatus != fetchStatus }, 5000, 1000) diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsCurrencySpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsCurrencySpec.groovy index b569514d0c4..ef96988aa06 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsCurrencySpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsCurrencySpec.groovy @@ -9,6 +9,7 @@ import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.ErrorType import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.PbsConfig +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.util.CurrencyUtil import org.prebid.server.functional.util.PBSUtils @@ -17,8 +18,8 @@ import static org.prebid.server.functional.model.Currency.EUR import static org.prebid.server.functional.model.Currency.GBP import static org.prebid.server.functional.model.Currency.JPY import static org.prebid.server.functional.model.Currency.USD -import static org.prebid.server.functional.model.request.auction.FetchStatus.NONE -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.NONE +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.request.auction.Location.FETCH import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID @@ -26,14 +27,15 @@ class PriceFloorsCurrencySpec extends PriceFloorsBaseSpec { private static final String GENERAL_ERROR_METRIC = "price-floors.general.err" + private static final PbsContainerConfig PBS_CONFIG = new PbsContainerConfig(FLOORS_CONFIG + PbsConfig.currencyConverterConfig) private static PrebidServerService currencyFloorsPbsService def setupSpec() { - currencyFloorsPbsService = pbsServiceFactory.getService(FLOORS_CONFIG + PbsConfig.currencyConverterConfig) + currencyFloorsPbsService = pbsServiceFactory.getService(PBS_CONFIG) } def cleanupSpec() { - pbsServiceFactory.removeContainer(FLOORS_CONFIG + PbsConfig.currencyConverterConfig) + pbsServiceFactory.removeContainer(PBS_CONFIG) } def "PBS should update bidFloor, bidFloorCur for signalling when request.cur is specified"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsFetchingSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsFetchingSpec.groovy index fcfa39f6e9d..bc060d2b129 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsFetchingSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsFetchingSpec.groovy @@ -22,10 +22,10 @@ import static org.prebid.server.functional.model.pricefloors.Country.MULTIPLE import static org.prebid.server.functional.model.pricefloors.MediaType.BANNER import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE -import static org.prebid.server.functional.model.request.auction.FetchStatus.ERROR -import static org.prebid.server.functional.model.request.auction.FetchStatus.INPROGRESS -import static org.prebid.server.functional.model.request.auction.FetchStatus.NONE -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.ERROR +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.INPROGRESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.NONE +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.request.auction.Location.FETCH import static org.prebid.server.functional.model.request.auction.Location.NO_DATA import static org.prebid.server.functional.model.request.auction.Location.REQUEST diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy index bd892ca8746..aa7dbc653b9 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy @@ -59,7 +59,7 @@ import static org.prebid.server.functional.model.pricefloors.PriceFloorField.SIZ import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP import static org.prebid.server.functional.model.request.auction.DistributionChannel.DOOH import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE -import static org.prebid.server.functional.model.request.auction.FetchStatus.ERROR +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.ERROR import static org.prebid.server.functional.model.request.auction.Location.NO_DATA import static org.prebid.server.functional.model.response.auction.BidRejectionReason.RESPONSE_REJECTED_DUE_TO_PRICE_FLOOR import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsSignalingSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsSignalingSpec.groovy index 9ad4114c212..035775ff809 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsSignalingSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsSignalingSpec.groovy @@ -16,6 +16,7 @@ import org.prebid.server.functional.model.request.auction.Imp import org.prebid.server.functional.model.request.auction.Video import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.model.response.auction.MediaType +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.util.PBSUtils import java.math.RoundingMode @@ -30,7 +31,7 @@ import static org.prebid.server.functional.model.pricefloors.MediaType.VIDEO import static org.prebid.server.functional.model.pricefloors.PriceFloorField.MEDIA_TYPE import static org.prebid.server.functional.model.pricefloors.PriceFloorField.SITE_DOMAIN import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP -import static org.prebid.server.functional.model.request.auction.FetchStatus.SUCCESS +import static org.prebid.server.functional.model.request.auction.AnalyticTagStatus.SUCCESS import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { @@ -666,8 +667,8 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { def accountConfig = getDefaultAccountConfigSettings().tap { auction.priceFloors.maxSchemaDims = MAX_SCHEMA_DIMENSIONS_SIZE } - def pbsFloorConfig = GENERIC_ALIAS_CONFIG + ["price-floors.enabled" : "true", - "settings.default-account-config": encode(accountConfig)] + def pbsFloorConfig = new PbsContainerConfig(GENERIC_ALIAS_CONFIG + ["price-floors.enabled" : "true", + "settings.default-account-config": encode(accountConfig)]) and: "Prebid server with floor config" def floorsPbsService = pbsServiceFactory.getService(pbsFloorConfig) @@ -707,9 +708,6 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { def metrics = floorsPbsService.sendCollectedMetricsRequest() assert metrics[INVALID_CONFIG_METRIC(bidRequest.accountId) as String] == 1 assert metrics[ALERT_GENERAL] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsFloorConfig) } def "PBS should emit warning when request has more schema.fields than default-account.fetch.max-schema-dims"() { @@ -723,8 +721,8 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { auction.priceFloors.fetch.maxSchemaDims = MAX_SCHEMA_DIMENSIONS_SIZE auction.priceFloors.maxSchemaDims = MAX_SCHEMA_DIMENSIONS_SIZE } - def pbsFloorConfig = GENERIC_ALIAS_CONFIG + ["price-floors.enabled" : "true", - "settings.default-account-config": encode(accountConfig)] + def pbsFloorConfig = new PbsContainerConfig(GENERIC_ALIAS_CONFIG + ["price-floors.enabled" : "true", + "settings.default-account-config": encode(accountConfig)]) and: "Prebid server with floor config" def floorsPbsService = pbsServiceFactory.getService(pbsFloorConfig) @@ -760,9 +758,6 @@ class PriceFloorsSignalingSpec extends PriceFloorsBaseSpec { def metrics = floorsPbsService.sendCollectedMetricsRequest() assert metrics[INVALID_CONFIG_METRIC(bidRequest.accountId) as String] == 1 assert metrics[ALERT_GENERAL] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsFloorConfig) } def "PBS should emit warning when request has more schema.fields than fetch.max-schema-dims"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/PrivacyBaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/PrivacyBaseSpec.groovy index 79ed11c5856..cc22da62876 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/PrivacyBaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/PrivacyBaseSpec.groovy @@ -38,6 +38,7 @@ import org.prebid.server.functional.model.request.auction.User import org.prebid.server.functional.model.request.auction.UserExt import org.prebid.server.functional.model.request.auction.UserExtData import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.testcontainers.scaffolding.VendorList import org.prebid.server.functional.tests.BaseSpec import org.prebid.server.functional.util.PBSUtils @@ -111,15 +112,15 @@ abstract class PrivacyBaseSpec extends BaseSpec { protected static final Integer MAX_INVALID_TCF_POLICY_VERSION = 63 protected static final Integer MIN_INVALID_TCF_POLICY_VERSION = 6 - protected static final Map GENERAL_PRIVACY_CONFIG = - GENERIC_CONFIG + GDPR_VENDOR_LIST_CONFIG + GENERIC_VENDOR_CONFIG + RETRY_POLICY_EXPONENTIAL_CONFIG + protected static final PbsContainerConfig GENERAL_PRIVACY_CONFIG = new PbsContainerConfig( + GENERIC_CONFIG + GDPR_VENDOR_LIST_CONFIG + GENERIC_VENDOR_CONFIG + RETRY_POLICY_EXPONENTIAL_CONFIG) protected static PrebidServerService privacyPbsService protected static PrebidServerService activityPbsService def setupSpec() { privacyPbsService = pbsServiceFactory.getService(GENERAL_PRIVACY_CONFIG + GDPR_EEA_COUNTRY) - activityPbsService = pbsServiceFactory.getService(OPENX_CONFIG + SETTING_CONFIG + GENERAL_PRIVACY_CONFIG) + activityPbsService = pbsServiceFactory.getService(GENERAL_PRIVACY_CONFIG + OPENX_CONFIG + SETTING_CONFIG) vendorListResponse.setResponse() } diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprAmpSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprAmpSpec.groovy index e24e8fdc563..cf1bd837219 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprAmpSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprAmpSpec.groovy @@ -359,9 +359,6 @@ class GdprAmpSpec extends PrivacyBaseSpec { assert getLogsByText(logs, "Created new TCF 2 vendor list for version " + "v${tcfPolicyVersion.vendorListVersion}.${tcfPolicyVersion.vendorListVersion}") - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(config) - where: tcfPolicyVersion << [TCF_POLICY_V2, TCF_POLICY_V4, TCF_POLICY_V5] } @@ -469,9 +466,6 @@ class GdprAmpSpec extends PrivacyBaseSpec { and: "Reset vendor list response" vendorListResponse.reset() - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(GENERAL_PRIVACY_CONFIG) - where: tcfPolicyVersion << [TCF_POLICY_V2, TCF_POLICY_V4, TCF_POLICY_V5] } @@ -703,9 +697,6 @@ class GdprAmpSpec extends PrivacyBaseSpec { def vendorList = defaultPrivacyPbsService.getValueFromContainer(properVendorListPath, VendorListConsent.class) assert vendorList.gvlSpecificationVersion == V3 - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(GENERAL_PRIVACY_CONFIG) - where: tcfPolicyVersion << [TCF_POLICY_V4, TCF_POLICY_V5] } diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprAuctionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprAuctionSpec.groovy index ffbbbcbbd79..e2b961c354e 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprAuctionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprAuctionSpec.groovy @@ -337,9 +337,6 @@ class GdprAuctionSpec extends PrivacyBaseSpec { assert getLogsByText(logs, "Created new TCF 2 vendor list for version " + "v${tcfPolicyVersion.vendorListVersion}.${tcfPolicyVersion.vendorListVersion}") - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(config) - where: tcfPolicyVersion << [TCF_POLICY_V2, TCF_POLICY_V4, TCF_POLICY_V5] } @@ -440,9 +437,6 @@ class GdprAuctionSpec extends PrivacyBaseSpec { and: "Reset vendor list response" vendorListResponse.reset() - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(GENERAL_PRIVACY_CONFIG) - where: tcfPolicyVersion << [TCF_POLICY_V2, TCF_POLICY_V4, TCF_POLICY_V5] } @@ -855,9 +849,6 @@ class GdprAuctionSpec extends PrivacyBaseSpec { def vendorList = defaultPrivacyPbsService.getValueFromContainer(properVendorListPath, VendorListConsent.class) assert vendorList.gvlSpecificationVersion == V3 - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(GENERAL_PRIVACY_CONFIG) - where: tcfPolicyVersion << [TCF_POLICY_V4, TCF_POLICY_V5] } @@ -1190,9 +1181,6 @@ class GdprAuctionSpec extends PrivacyBaseSpec { def metrics = pbsWithLiveGvlSetup.sendCollectedMetricsRequest() assert !metrics[TEMPLATE_ADAPTER_DISALLOWED_COUNT.getValue(bidRequest, FETCH_BIDS)] - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(REFRESH_LIVE_VENDOR_LIST_CONFIG) - where: gvlDeletedDate << [null, ZonedDateTime.now().plusYears(1)] } @@ -1248,9 +1236,6 @@ class GdprAuctionSpec extends PrivacyBaseSpec { def metrics = pbsWithLiveGvlSetup.sendCollectedMetricsRequest() assert metrics[TEMPLATE_ADAPTER_DISALLOWED_COUNT.getValue(bidRequest, FETCH_BIDS)] == 1 - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(REFRESH_LIVE_VENDOR_LIST_CONFIG) - where: liveGvlDeletedDate | requestGvlDeletedDate ZonedDateTime.now().minusSeconds(1) | ZonedDateTime.now().plusYears(1) @@ -1304,9 +1289,6 @@ class GdprAuctionSpec extends PrivacyBaseSpec { and: "Disallowed metrics should be updated" def metrics = pbsWithLiveGvlSetup.sendCollectedMetricsRequest() assert metrics[TEMPLATE_ADAPTER_DISALLOWED_COUNT.getValue(bidRequest, FETCH_BIDS)] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(REFRESH_LIVE_VENDOR_LIST_CONFIG) } def "PBS should treat vendor as valid when deleted only in intermediate GVL versions"() { @@ -1369,9 +1351,6 @@ class GdprAuctionSpec extends PrivacyBaseSpec { and: "Disallowed metrics shouldn't be updated" def metrics = pbsWithLiveGvlSetup.sendCollectedMetricsRequest() assert metrics[TEMPLATE_ADAPTER_DISALLOWED_COUNT.getValue(bidRequest, FETCH_BIDS)] == 0 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(config) } private static void downloadLiveGvtList( diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprSetUidSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprSetUidSpec.groovy index a4ff12f45bd..32d843e4a63 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprSetUidSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/gdpr/GdprSetUidSpec.groovy @@ -12,6 +12,7 @@ import org.prebid.server.functional.model.response.cookiesync.UserSyncInfo import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.Dependencies +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.tests.privacy.PrivacyBaseSpec import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.TcfConsent @@ -32,9 +33,9 @@ class GdprSetUidSpec extends PrivacyBaseSpec { private static final String USER_SYNC_URL = "$Dependencies.networkServiceContainer.rootUri/generic-usersync" private static final UserSyncInfo.Type USER_SYNC_TYPE = REDIRECT - private static final Map VENDOR_GENERIC_PBS_CONFIG = GENERIC_VENDOR_CONFIG + + private static final PbsContainerConfig VENDOR_GENERIC_PBS_CONFIG = new PbsContainerConfig(GENERIC_VENDOR_CONFIG + ["gdpr.purposes.p1.enforce-purpose" : NO.value, - "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : USER_SYNC_URL] + "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : USER_SYNC_URL]) private static final String TCF_ERROR_MESSAGE = "The gdpr_consent param prevents cookies from being saved" private static final int UNAVAILABLE_FOR_LEGAL_REASONS_CODE = 451 @@ -119,9 +120,6 @@ class GdprSetUidSpec extends PrivacyBaseSpec { assert response.uidsCookie.tempUIDs[GENER_X].uid == setuidRequest.uid assert response.responseBody == ResourceUtil.readByteArrayFromClassPath("org/prebid/server/functional/tracking-pixel.png") - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid should failed with tcf when dgpr value is invalid"() { @@ -252,9 +250,6 @@ class GdprSetUidSpec extends PrivacyBaseSpec { and: "Metric should be increased usersync.BIDDER.tcf.blocked" def metric = prebidServerService.sendCollectedMetricsRequest() assert metric["usersync.${GENERIC.value}.tcf.blocked"] == 1 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid shouldn't failed with tcf when purpose access device not enforced for host and host-vendor-id empty"() { @@ -299,9 +294,6 @@ class GdprSetUidSpec extends PrivacyBaseSpec { assert response.uidsCookie.tempUIDs[GENERIC].uid == setuidRequest.uid assert response.responseBody == ResourceUtil.readByteArrayFromClassPath("org/prebid/server/functional/tracking-pixel.png") - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS setuid shouldn't failed with purpose access device enforced for account when bidder included in vendorExceptions"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/gpp/GppCookieSyncSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/gpp/GppCookieSyncSpec.groovy index 46369e28503..1406d485634 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/gpp/GppCookieSyncSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/gpp/GppCookieSyncSpec.groovy @@ -12,6 +12,7 @@ import org.prebid.server.functional.model.response.cookiesync.UserSyncInfo import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.testcontainers.Dependencies +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.tests.BaseSpec import org.prebid.server.functional.util.HttpUtil import org.prebid.server.functional.util.PBSUtils @@ -29,6 +30,7 @@ import static org.prebid.server.functional.model.request.GppSectionId.TCF_EU_V2 import static org.prebid.server.functional.model.request.GppSectionId.USP_V1 import static org.prebid.server.functional.model.response.cookiesync.UserSyncInfo.Type.IFRAME import static org.prebid.server.functional.model.response.cookiesync.UserSyncInfo.Type.REDIRECT +import static org.prebid.server.functional.testcontainers.Dependencies.networkServiceContainer import static org.prebid.server.functional.util.privacy.CcpaConsent.Signal.ENFORCED import static org.prebid.server.functional.util.privacy.TcfConsent.GENERIC_VENDOR_ID import static org.prebid.server.functional.util.privacy.TcfConsent.PurposeId.DEVICE_ACCESS @@ -36,18 +38,18 @@ import static org.prebid.server.functional.util.privacy.TcfConsent.PurposeId.DEV class GppCookieSyncSpec extends BaseSpec { private static final UserSyncInfo.Type USER_SYNC_TYPE = REDIRECT - private static final String USER_SYNC_URL = "$Dependencies.networkServiceContainer.rootUri/generic-usersync" + private static final String USER_SYNC_URL = "$networkServiceContainer.rootUri/generic-usersync" private static final GppSectionId FIRST_GPP_SECTION = PBSUtils.getRandomEnum(GppSectionId.class) private static final GppSectionId SECOND_GPP_SECTION = PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION]) - private static final Map GENERIC_CONFIG = [ - "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, - "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : USER_SYNC_URL] - private static final Map GENERIC_WITH_SKIP_CONFIG = [ - "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, - "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : "$Dependencies.networkServiceContainer.rootUri/generic-usersync&redir={redirect_url}".toString(), - "adapters.${GENERIC.value}.usersync.skipwhen.gdpr" : 'true', - "adapters.${GENERIC.value}.usersync.skipwhen.gpp_sid" : "${FIRST_GPP_SECTION.value}, ${SECOND_GPP_SECTION.value}".toString()] + private static final PbsContainerConfig GENERIC_CONFIG = new PbsContainerConfig([ + "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, + "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url": USER_SYNC_URL]) + private static final PbsContainerConfig GENERIC_WITH_SKIP_CONFIG = new PbsContainerConfig([ + "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, + "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url": "$networkServiceContainer.rootUri/generic-usersync&redir={redirect_url}".toString(), + "adapters.${GENERIC.value}.usersync.skipwhen.gdpr" : 'true', + "adapters.${GENERIC.value}.usersync.skipwhen.gpp_sid" : "${FIRST_GPP_SECTION.value}, ${SECOND_GPP_SECTION.value}".toString()]) private static PrebidServerService prebidServerService = pbsServiceFactory.getService(GENERIC_CONFIG) private static PrebidServerService prebidServerServiceWithSkipConfig = pbsServiceFactory.getService(GENERIC_WITH_SKIP_CONFIG + GENERIC_ALIAS_CONFIG) @@ -227,7 +229,8 @@ class GppCookieSyncSpec extends BaseSpec { def "PBS should return empty gpp and gppSid in usersync url when gpp and gppSid is not present in request"() { given: "Pbs config with usersync.#userSyncFormat.url" - def pbsConfig = ["adapters.generic.usersync.${userSyncFormat.value}.url" : "$Dependencies.networkServiceContainer.rootUri/generic-usersync&redir={redirect_url}".toString()] + def pbsConfig = new PbsContainerConfig( + ["adapters.generic.usersync.${userSyncFormat.value}.url": "$networkServiceContainer.rootUri/generic-usersync&redir={redirect_url}".toString()]) def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Default CookieSyncRequest without gpp and gppSid" @@ -253,7 +256,8 @@ class GppCookieSyncSpec extends BaseSpec { def "PBS should populate gpp and gppSid in usersync url when gpp and gppSid is present in request"() { given: "Pbs config with usersync.#userSyncFormat.url" - def pbsConfig = ["adapters.generic.usersync.${userSyncFormat.value}.url" : "$Dependencies.networkServiceContainer.rootUri/generic-usersync&redir={redirect_url}".toString()] + def pbsConfig = new PbsContainerConfig( + ["adapters.generic.usersync.${userSyncFormat.value}.url": "$networkServiceContainer.rootUri/generic-usersync&redir={redirect_url}".toString()]) def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Default CookieSyncRequest with gpp and gppSid" @@ -272,9 +276,6 @@ class GppCookieSyncSpec extends BaseSpec { assert HttpUtil.findUrlParameterValue(bidderStatus.userSync?.url, "gpp") == gpp assert HttpUtil.findUrlParameterValue(bidderStatus.userSync?.url, "gpp_sid") == gppSid - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) - where: userSyncFormat << [REDIRECT, IFRAME] } @@ -404,10 +405,10 @@ class GppCookieSyncSpec extends BaseSpec { def "PBS shouldn't emit error message when request does contain gdpr config and global skip gdpr config disabled for adapter"() { given: "Pbs config with usersync.#userSyncFormat.url" - def pbsConfig = [ - "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, - "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : USER_SYNC_URL, - "adapters.${GENERIC.value}.usersync.skipwhen.gdpr" : 'false'] + def pbsConfig = new PbsContainerConfig([ + "adapters.${GENERIC.value}.meta-info.vendor-id" : GENERIC_VENDOR_ID as String, + "adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url": USER_SYNC_URL, + "adapters.${GENERIC.value}.usersync.skipwhen.gdpr" : 'false']) def prebidServerService = pbsServiceFactory.getService(pbsConfig) and: "Default CookieSyncRequest with gdpr config" @@ -438,9 +439,6 @@ class GppCookieSyncSpec extends BaseSpec { and: "Response shouldn't contains any error" assert !bidderStatus.error - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(pbsConfig) } def "PBS shouldn't emit error message when request does contain gdpr config and global skip gdpr config default for adapter"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfBaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfBaseSpec.groovy index e51e71c1b7a..9eca94248c9 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfBaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfBaseSpec.groovy @@ -8,7 +8,7 @@ import org.prebid.server.functional.model.request.auction.Activity import org.prebid.server.functional.model.request.auction.ActivityRule import org.prebid.server.functional.model.request.auction.AllowActivities import org.prebid.server.functional.model.request.auction.Condition -import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.tests.privacy.PrivacyBaseSpec import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.TcfUtils @@ -26,26 +26,39 @@ import static org.prebid.server.functional.util.privacy.TcfConsent.RestrictionTy class TcfBaseSpec extends PrivacyBaseSpec { - private static String prepareEncodeResponseBodyWithPurposesOnly = getVendorListContent(true, false, false) - private static String prepareEncodeResponseBodyWithLegIntPurposes = getVendorListContent(false, true, false) - private static String prepareEncodeResponseBodyWithLegIntAndFlexiblePurposes = getVendorListContent(false, true, true) - private static String prepareEncodeResponseBodyWithPurposesAndFlexiblePurposes = getVendorListContent(true, false, true) - protected static final int PURPOSES_ONLY_GVL_VERSION = PBSUtils.getRandomNumber(0, 4095) - protected static final int LEG_INT_PURPOSES_ONLY_GVL_VERSION = PBSUtils.getRandomNumberWithExclusion(PURPOSES_ONLY_GVL_VERSION, 0, 4095) - protected static final int LEG_INT_AND_FLEXIBLE_PURPOSES_GVL_VERSION = PBSUtils.getRandomNumberWithExclusion([PURPOSES_ONLY_GVL_VERSION, LEG_INT_PURPOSES_ONLY_GVL_VERSION], 0, 4095) - protected static final int PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION = PBSUtils.getRandomNumberWithExclusion([PURPOSES_ONLY_GVL_VERSION, LEG_INT_PURPOSES_ONLY_GVL_VERSION, LEG_INT_AND_FLEXIBLE_PURPOSES_GVL_VERSION], 0, 4095) - protected static Map GLV_LISTS_FILES = [(getVendorListPath(PURPOSES_ONLY_GVL_VERSION)) : Transferable.of(prepareEncodeResponseBodyWithPurposesOnly), - (getVendorListPath(LEG_INT_PURPOSES_ONLY_GVL_VERSION)) : Transferable.of(prepareEncodeResponseBodyWithLegIntPurposes), - (getVendorListPath(LEG_INT_AND_FLEXIBLE_PURPOSES_GVL_VERSION)): Transferable.of(prepareEncodeResponseBodyWithLegIntAndFlexiblePurposes), - (getVendorListPath(PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION)): Transferable.of(prepareEncodeResponseBodyWithPurposesAndFlexiblePurposes) + protected static final int LEG_INT_PURPOSES_ONLY_GVL_VERSION = + PBSUtils.getRandomNumberWithExclusion(PURPOSES_ONLY_GVL_VERSION, 0, 4095) + protected static final int LEG_INT_AND_FLEXIBLE_PURPOSES_GVL_VERSION = + PBSUtils.getRandomNumberWithExclusion( + [PURPOSES_ONLY_GVL_VERSION, LEG_INT_PURPOSES_ONLY_GVL_VERSION], 0, 4095) + protected static final int PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION = + PBSUtils.getRandomNumberWithExclusion( + [PURPOSES_ONLY_GVL_VERSION, LEG_INT_PURPOSES_ONLY_GVL_VERSION, + LEG_INT_AND_FLEXIBLE_PURPOSES_GVL_VERSION], 0, 4095) + + protected static final Map GVL_LISTS_FILES = [ + (getVendorListPath(PURPOSES_ONLY_GVL_VERSION)) : Transferable.of(getVendorListContent(true, false, false)), + (getVendorListPath(LEG_INT_PURPOSES_ONLY_GVL_VERSION)) : Transferable.of(getVendorListContent(false, true, false)), + (getVendorListPath(LEG_INT_AND_FLEXIBLE_PURPOSES_GVL_VERSION)): Transferable.of(getVendorListContent(false, true, true)), + (getVendorListPath(PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION)): Transferable.of(getVendorListContent(true, false, true)) + ].asImmutable() + + private static final Map GDPR_RESTRICTION_CONFIG = [ + 'gdpr.strict-disclosed-vendors-treatment': 'false' ] - private static final Map GDPR_RESTRICTION_CONFIG = ["gdpr.strict-disclosed-vendors-treatment": 'false'] - protected static final Map VENDOR_LIST_EMPTY_CONFIG = ["gdpr.vendorlist.v2.http-endpoint-template": null, - "gdpr.vendorlist.v3.http-endpoint-template": null] + protected static final PbsContainerConfig VENDOR_LIST_EMPTY_CONFIG = new PbsContainerConfig([ + 'gdpr.vendorlist.v2.http-endpoint-template': null, + 'gdpr.vendorlist.v3.http-endpoint-template': null + ]) - protected static final Map TCF_BASE_CONFIG = SETTING_CONFIG + GENERIC_VENDOR_CONFIG + GENERIC_CONFIG + GDPR_RESTRICTION_CONFIG + protected static final PbsContainerConfig TCF_BASE_CONFIG = new PbsContainerConfig( + [:] << SETTING_CONFIG + << GENERIC_VENDOR_CONFIG + << GENERIC_CONFIG + << GDPR_RESTRICTION_CONFIG + ) protected static List getBasicTcfCompanyBasedEnforcementRequirements(Purpose purpose) { [new EnforcementRequirement(purpose: purpose, @@ -115,13 +128,13 @@ class TcfBaseSpec extends PrivacyBaseSpec { vendorIdGvl: GENERIC_VENDOR_ID, restrictionType: [UNDEFINED], vendorConsentBitField: GENERIC_VENDOR_ID, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, vendorIdGvl: GENERIC_VENDOR_ID, restrictionType: [REQUIRE_CONSENT], vendorConsentBitField: GENERIC_VENDOR_ID, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), ] } @@ -180,7 +193,7 @@ class TcfBaseSpec extends PrivacyBaseSpec { restrictionType: [UNDEFINED], purposesLITransparency: true, enforceVendor: false, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, @@ -188,7 +201,7 @@ class TcfBaseSpec extends PrivacyBaseSpec { restrictionType: [UNDEFINED], purposesLITransparency: true, vendorLegitimateInterestBitField: GENERIC_VENDOR_ID, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, @@ -196,14 +209,14 @@ class TcfBaseSpec extends PrivacyBaseSpec { restrictionType: [REQUIRE_LEGITIMATE_INTEREST], purposesLITransparency: true, vendorLegitimateInterestBitField: GENERIC_VENDOR_ID, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, vendorIdGvl: GENERIC_VENDOR_ID, restrictionType: [REQUIRE_LEGITIMATE_INTEREST], purposesLITransparency: true, enforceVendor: false, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]) ] } @@ -301,27 +314,27 @@ class TcfBaseSpec extends PrivacyBaseSpec { restrictionType: [UNDEFINED], enforcePurpose: NO, enforceVendor: false, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, vendorIdGvl: GENERIC_VENDOR_ID, restrictionType: [UNDEFINED], enforceVendor: false, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, vendorIdGvl: GENERIC_VENDOR_ID, restrictionType: [UNDEFINED], enforcePurpose: NO, vendorConsentBitField: GENERIC_VENDOR_ID, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, vendorIdGvl: GENERIC_VENDOR_ID, restrictionType: [UNDEFINED], enforcePurpose: NO, enforceVendor: false, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, @@ -329,20 +342,20 @@ class TcfBaseSpec extends PrivacyBaseSpec { restrictionType: [REQUIRE_CONSENT], enforcePurpose: NO, enforceVendor: false, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, vendorIdGvl: GENERIC_VENDOR_ID, restrictionType: [REQUIRE_CONSENT], enforceVendor: false, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, vendorIdGvl: GENERIC_VENDOR_ID, restrictionType: [REQUIRE_CONSENT], enforcePurpose: NO, vendorConsentBitField: GENERIC_VENDOR_ID, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, @@ -350,7 +363,7 @@ class TcfBaseSpec extends PrivacyBaseSpec { restrictionType: [REQUIRE_LEGITIMATE_INTEREST], enforcePurpose: NO, enforceVendor: false, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, @@ -393,7 +406,7 @@ class TcfBaseSpec extends PrivacyBaseSpec { restrictionType: [UNDEFINED], enforcePurpose: NO, vendorLegitimateInterestBitField: GENERIC_VENDOR_ID, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]), new EnforcementRequirement(purpose: isPurposeExcludedAndListRandom ? getRandomPurposeWithExclusion(purpose) : purpose, @@ -401,7 +414,7 @@ class TcfBaseSpec extends PrivacyBaseSpec { restrictionType: [REQUIRE_LEGITIMATE_INTEREST], enforcePurpose: NO, vendorLegitimateInterestBitField: GENERIC_VENDOR_ID, - vendorListVersion: PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION, + vendorListVersion: PURPOSES_AND_FLEXIBLE_PURPOSES_GVL_VERSION, disclosedVendorsId: [GENERIC_VENDOR_ID]) ] } diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfFullTransmitEidsActivitiesSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfFullTransmitEidsActivitiesSpec.groovy index 476cc206f3b..c149842068c 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfFullTransmitEidsActivitiesSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfFullTransmitEidsActivitiesSpec.groovy @@ -21,7 +21,7 @@ class TcfFullTransmitEidsActivitiesSpec extends TcfBaseSpec { private static PrebidServerService privacyPbsServiceWithMultipleGvl def setupSpec() { - privacyPbsServiceWithMultipleGvl = pbsServiceFactory.getService(GENERAL_PRIVACY_CONFIG, GLV_LISTS_FILES) + privacyPbsServiceWithMultipleGvl = pbsServiceFactory.getService(GENERAL_PRIVACY_CONFIG, GVL_LISTS_FILES) } def cleanupSpec() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfGeneralSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfGeneralSpec.groovy index 4892e19fc37..cea771c8655 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfGeneralSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TcfGeneralSpec.groovy @@ -7,6 +7,7 @@ import org.prebid.server.functional.model.config.PurposeConfig import org.prebid.server.functional.model.privacy.EnforcementRequirement import org.prebid.server.functional.model.response.auction.NoBidResponse import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.util.PBSUtils import org.prebid.server.functional.util.privacy.TcfConsent import org.prebid.server.functional.util.privacy.TcfUtils @@ -20,22 +21,30 @@ import static org.prebid.server.functional.util.privacy.TcfConsent.GENERIC_VENDO class TcfGeneralSpec extends TcfBaseSpec { - private final static ZonedDateTime TCF_2_3_ENFORCEMENT_DATE = ZonedDateTime.parse("2026-03-01T00:00:00Z") - private final static Map STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG = TCF_BASE_CONFIG + ["gdpr.strict-disclosed-vendors-treatment": 'true'] - private final static TCF_NO_DISCLOSED_VENDORS_METRIC = 'privacy.tcf.no-disclosed-vendors' - private final static DISCLOSED_VENDORS_MESSAGE = 'Invalid TCF string: `disclosedVendors` list is empty.' + + private static final ZonedDateTime TCF_2_3_ENFORCEMENT_DATE = ZonedDateTime.parse("2026-03-01T00:00:00Z") + + private static final PbsContainerConfig STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG = TCF_BASE_CONFIG + + ['gdpr.strict-disclosed-vendors-treatment': 'true'] + + private static final PbsContainerConfig BASE_STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG = STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG + + VENDOR_LIST_EMPTY_CONFIG + + private static final PbsContainerConfig FULL_STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG = STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG.withFiles(GVL_LISTS_FILES) private static PrebidServerService pbsWithoutGvlVendorsWithStrictDvTreatment private static PrebidServerService pbsWithMultipleGvlListsWithStrictDvTreatment def setupSpec() { - pbsWithoutGvlVendorsWithStrictDvTreatment = pbsServiceFactory.getService(STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG + VENDOR_LIST_EMPTY_CONFIG) - pbsWithMultipleGvlListsWithStrictDvTreatment = pbsServiceFactory.getService(STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG, GLV_LISTS_FILES) + pbsWithoutGvlVendorsWithStrictDvTreatment = + pbsServiceFactory.getService(BASE_STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG) + pbsWithMultipleGvlListsWithStrictDvTreatment = + pbsServiceFactory.getService(FULL_STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG) } def cleanupSpec() { - pbsServiceFactory.removeContainer(STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG + VENDOR_LIST_EMPTY_CONFIG) - pbsServiceFactory.removeContainer(STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG) + pbsServiceFactory.removeContainer(BASE_STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG) + pbsServiceFactory.removeContainer(FULL_STRICT_DISCLOSED_VENDOR_TREATMENT_CONFIG) } def "PBS should accept base consent when disclosedVendors includes vendor after TCF v2.3 enforcement"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TransmitEidsOrtbConverterActivitiesSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TransmitEidsOrtbConverterActivitiesSpec.groovy index a1871f090e3..9c0968b759d 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TransmitEidsOrtbConverterActivitiesSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/privacy/tcf/TransmitEidsOrtbConverterActivitiesSpec.groovy @@ -7,6 +7,7 @@ import org.prebid.server.functional.model.request.auction.AllowActivities import org.prebid.server.functional.model.request.auction.Condition import org.prebid.server.functional.model.request.auction.Eid import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.testcontainers.container.PbsContainerConfig import org.prebid.server.functional.util.privacy.TcfUtils import static org.prebid.server.functional.model.bidder.BidderName.GENERIC @@ -25,18 +26,19 @@ import static org.prebid.server.functional.model.request.auction.TraceLevel.VERB class TransmitEidsOrtbConverterActivitiesSpec extends TcfBaseSpec { - private final static Map ORTB_2_5_TCF_CONFIG = TCF_BASE_CONFIG + ["adapters.generic.ortb-version": "2.5"] + private final static PbsContainerConfig ORTB_2_5_TCF_CONFIG = new PbsContainerConfig(TCF_BASE_CONFIG + ["adapters.generic.ortb-version": "2.5"]) + private final static PbsContainerConfig ORTB_2_5_FULL_TCF_CONFIG = new PbsContainerConfig(TCF_BASE_CONFIG + ["adapters.generic.ortb-version": "2.5"], GVL_LISTS_FILES) private static PrebidServerService activityPbsServiceExcludeGvlWithElderOrtb private static PrebidServerService privacyPbsServiceWithMultipleGvlWithElderOrtb def setupSpec() { activityPbsServiceExcludeGvlWithElderOrtb = pbsServiceFactory.getService(ORTB_2_5_TCF_CONFIG + VENDOR_LIST_EMPTY_CONFIG) - privacyPbsServiceWithMultipleGvlWithElderOrtb = pbsServiceFactory.getService(ORTB_2_5_TCF_CONFIG, GLV_LISTS_FILES) + privacyPbsServiceWithMultipleGvlWithElderOrtb = pbsServiceFactory.getService(ORTB_2_5_FULL_TCF_CONFIG) } def cleanupSpec() { pbsServiceFactory.removeContainer(ORTB_2_5_TCF_CONFIG + VENDOR_LIST_EMPTY_CONFIG) - pbsServiceFactory.removeContainer(ORTB_2_5_TCF_CONFIG) + pbsServiceFactory.removeContainer(ORTB_2_5_FULL_TCF_CONFIG) } def "PPBS should leave ext.eids for older ORTB versions when requireConsent is enabled and #enforcementRequirements.purpose have any basic consent"() { diff --git a/src/test/groovy/org/prebid/server/functional/util/ContainerFileUtil.groovy b/src/test/groovy/org/prebid/server/functional/util/ContainerFileUtil.groovy new file mode 100644 index 00000000000..709ee5a9470 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/util/ContainerFileUtil.groovy @@ -0,0 +1,20 @@ +package org.prebid.server.functional.util + +import org.testcontainers.images.builder.Transferable + +class ContainerFileUtil implements ObjectMapperWrapper { + + static Map yamlFile(String path, Object content) { + [(path): Transferable.of(encodeYaml(content))] + } + + static Map jsonFile(String path, Object content) { + [(path): Transferable.of(encode(content))] + } + + static Map emptyFolders(String... paths) { + paths.collectEntries { path -> + [("$path/.keep".toString()): Transferable.of(new byte[0], 010755)] + } + } +} diff --git a/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy b/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy index cf7d96a6b04..85755c35899 100644 --- a/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy +++ b/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy @@ -2,6 +2,7 @@ package org.prebid.server.functional.util import org.apache.commons.lang3.RandomStringUtils import org.prebid.server.functional.model.request.auction.BidRequest +import org.testcontainers.images.builder.Transferable import java.math.RoundingMode import java.nio.file.Files diff --git a/src/test/groovy/org/prebid/server/functional/util/SystemProperties.groovy b/src/test/groovy/org/prebid/server/functional/util/SystemProperties.groovy index 410f9736991..765f03187db 100644 --- a/src/test/groovy/org/prebid/server/functional/util/SystemProperties.groovy +++ b/src/test/groovy/org/prebid/server/functional/util/SystemProperties.groovy @@ -4,6 +4,8 @@ class SystemProperties { public static final String PBS_VERSION = System.getProperty("pbs.version")?.split("-")?.first() public static final boolean USE_FIXED_CONTAINER_PORTS = getPropertyOrDefault("tests.fixed-container-ports", false) + public static final boolean DEBUG_ENABLED = getPropertyOrDefault("tests.debug.enable", false) + public static final int MAX_CONTAINER = getPropertyOrDefault("tests.max-container-count", 5) public static final int DEFAULT_TIMEOUT = 5000 static int getPropertyOrDefault(String property, int defaultValue) { diff --git a/src/test/groovy/org/prebid/server/functional/util/privacy/model/State.groovy b/src/test/groovy/org/prebid/server/functional/util/privacy/model/State.groovy index 9af51dceea3..1e56f4a4d88 100644 --- a/src/test/groovy/org/prebid/server/functional/util/privacy/model/State.groovy +++ b/src/test/groovy/org/prebid/server/functional/util/privacy/model/State.groovy @@ -8,8 +8,7 @@ enum State { //USA states ALABAMA("AL"), ALASKA("AK"), ARIZONA("AZ"); - - final String abbreviation; + final String abbreviation State(String abbreviation) { this.abbreviation = abbreviation