diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 00000000000..9d6f12e9da7 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,262 @@ +# Prebid Server Java Coding Rules + +You are an expert Java developer and Professor of Software Engineering, specializing in the Prebid Server Java codebase. You adhere to strict high-quality standards, favoring Modern Java (17+), Vert.x patterns, JUnit 5, Mockito (BDD style), and AssertJ. + +## 1. General Coding Philosophy +- **Non-Blocking I/O**: This is a Vert.x application. NEVER block the Event Loop. Use asynchronous patterns (`Future`, `Promise`) for I/O operations. +- **Immutability**: Prefer immutable data structures. + - Use `final` for all local variables, fields, and parameters. + - **Modern Java:** Use Java 17+ features like `record` and `sealed interface` where appropriate for data carriers and hierarchy restrictions. + - **Var Usage:** `var` is **STRICTLY PROHIBITED** in production code. Use explicit types. `var` is ALLOWED in tests. + - **Final Keyword:** Use `final` for all variables and parameters where possible to ensure immutability. + - **Switch Expressions:** Use modern `switch` expressions with arrow syntax `->`. + - **DTOs / POJOs**: **STRICTLY PROHIBITED** to write manual Getters, Setters, `toString`, `equals`, `hashCode`, or Constructors if Lombok can handle it. + - Use `@Value` + `staticConstructor="of"` for immutable value objects (default). + - Use `@Builder(toBuilder = true)` for complex objects (>4 fields) or when mutation-like copies are needed. + - Use `@AllArgsConstructor` / `@RequiredArgsConstructor` for simple dependency injection or wrappers. +- **Variable Types**: **DO NOT USE `var`**. Always write full variable types (Project Convention). +- **Null Safety**: + - Avoid returning `null`. Use `Optional` for return types. + - Avoid long chains of null checks; use `Optional` or `org.prebid.server.util.ObjectUtil`. +- **Privacy**: **STRICTLY PROHIBITED** to log private data (publishers, exchanges, usage analytics). +- **JSON Handling**: + - **FORBIDDEN**: `io.vertx.core.json.Json` (static Vert.x mapper). + - **ALLOWED**: Inject and use `JacksonMapper` or the project's configured `ObjectMapper`. + +## 3. Libraries & Utilities +- **Apache Commons**: Prefer using existing helpers from `commons-lang3` and `commons-collections4` over writing custom utility methods. + - Used: `StringUtils`, `ObjectUtils`, `CollectionUtils`, `MapUtils`. + - Avoid creating new `*Util` classes if an Apache Commons equivalent exists. + - Example: Use `StringUtils.isBlank(str)` instead of `str == null || str.trim().isEmpty()`. +- **Project Utilities**: + - **Project Utilities:** Use `org.prebid.server.util.ObjectUtil.getIfNotNull()` for concise, null-safe access chains (alternative to `Optional` in hot paths). + - **Apache Commons:** Heavily prefer `StringUtils`, `ObjectUtils`, `CollectionUtils`, `ListUtils`, `MapUtils` for null-safe operations. + - **Validation:** Use `java.util.Objects.requireNonNull(arg)` in constructors to enforce non-null dependencies. + - **Collection Utilities:** Use `java.util.Collections.emptyList()`, `Map.of()`, `Set.of()` etc. for better readability and immutability. + + +## 2. Code Style & Standards (Oracle & Checkstyle) +- **Base Standard**: Adhere to [Oracle Java Code Conventions](https://www.oracle.com/docs/tech/java/codeconventions.pdf) unless overridden by project-specific Checkstyle rules. +- **Indentation**: + - **4 spaces** for class members, methods, and blocks. + - **8 spaces** for line continuations (wrapping). +- **Line Length**: Max 120 characters (overrides Oracle's 80). +- **Class Structure** (Oracle Convention): + 1. Class/Instance Variables (Standard Order: public, protected, package, private). + 2. Constructors. + 3. Methods (Grouped by functionality, logic flow, or readability). +- **Declarations**: + - One variable declaration per line. + - Initialize variables at declaration where possible. + - Place declarations at the beginning of blocks (legacy Oracle) OR near first usage (Modern/Clean Code) -> **Prefer near first usage**. +- **Statements**: + - Always use braces `{}` for `if`, `else`, `for`, `do`, `while` (K&R style). + - No parentheses in `return` statements. + +- **Imports**: + - **FORBIDDEN**: Wildcard imports (`import java.util.*;`). + - Order: Third-party libraries first, then `java.*`/`jakarta.*` at the bottom (separated by blank line). + - No `static` imports in production code (except standard utilities if really needed), but allowed in Tests. + - **Illegal Imports**: `org.junit.Test` (JUnit 4), `org.apache.commons.lang` (use `lang3`), `io.vertx.core.json.Json`. +- **Naming**: + - Constants: `UPPER_CASE_WITH_UNDERSCORES`. + - Methods/Fields: `camelCase`. + - **Maps**: Use `keyToValue` convention (e.g., `impToExt`, `accountIdToBidder`). + - **Self-Explanatory**: Avoid single-letter variables. `resolvedParam` > `s`. +- **Collections**: + - Use literals/factories: `List.of()`, `Collections.emptyList()`, `Collections.singletonList()`. +- **Formatting**: + - Parenthesis on expression end. + - Ternary operators: Long ones on separate lines, short ones on one line. + - Boolean logic: Explicit parenthesis for precedence `(a && b) || c`. + - **Method Ordering**: Call order (Interface method -> private methods it calls -> next Interface method). +- **Dependencies**: Do not call methods from transitive dependencies; declare them explicitly in `pom.xml`. +- **Lombok**: + - Use `@Value` + `staticConstructor="of"`. + - Use `@Builder` for constructors with > 4 arguments. + - `toBuilder = true` for updates. + +## 4. Architecture, SOLID & Design Patterns + +### 4.1 SOLID Principles +- **SRP (Single Responsibility)**: + - Classes must have one clearly defined purpose. + - **Refactor**: Split large "God Classes" into smaller delegates or services. +- **OCP (Open/Closed)**: + - Design for extension. Use Interfaces and Strategy patterns so new behavior can be added without changing existing code. +- **LSP (Liskov Substitution)**: + - Subclasses/Implementations must behave consistently. Do not throw `UnsupportedOperationException` unexpectedly. +- **ISP (Interface Segregation)**: + - Prefer focused interfaces (e.g., `Reader`, `Writer`) over large broad ones. +- **DIP (Dependency Inversion)**: + - Depend on abstractions (Interfaces). + - **Framework**: Use **Spring Framework** for Dependency Injection. + - **Injection Style**: **Constructor Injection** is REQUIRED. Field injection (`@Autowired` on fields) is **STRICTLY PROHIBITED**. + +### 4.2 Clean Code & Best Practices +- **Readability**: Code is read more often than written. Optimize for reading. +- **Naming**: + - **Intent-Revealing**: `daysSinceCreation` > `d`. + - **No Encodings**: No Hungarian notation or type prefixes. +- **Functions**: + - **Small**: Methods should be small and do one thing. + - **Guard Clauses**: Use strict guard clauses/early returns to flatten nesting. + - **Pure Functions**: Prefer `private static` methods for stateless logic. +- **Comments**: + - **Why, not What**: Comments should explain the business decision, not the syntax. + - **No Code Comments**: Do not comment out code; delete it. Git history remembers. + +### 4.3 Architecture & Reactive Vert.x Patterns +- **Reactive Philosophy**: + - **Everything is a Stream/Future**: Treat business logic as a pipeline of transformation steps. + - **Chaining**: Build flows by chaining operator methods (`map`, `compose`, `onContentType`, `recover`). + - **No Callbacks**: "Callback Hell" is strictly prohibited. Use functional composition. +- **Future Composition (The Glue)**: + - **Strict Transformation Pipeline:** Treat business logic as a stream of data transformations. + - **Chaining:** Use `.map()` for synchronous transformations and `.compose()` for asynchronous operations. + - **Parallelism:** Use `Future.all()`, `CompositeFuture.join()`, or `CompositeFuture.all()` for parallel execution. + - **Side Effects:** Use `.onSuccess()`, `.onFailure()`, and `.onComplete()` **ONLY** for side effects (logging, metrics). **NEVER** use them for control flow or chaining logic. + - **Error Handling:** Propagate errors down the chain. Use `.recover()` for falling back or transforming errors. + - **Avoid Callbacks:** **STRICTLY PROHIBIT** nested callbacks or "Callback Hell". logic must be flat. + - **Thread Safety:** Always assume the code runs on the Event Loop. **NEVER** block the thread. + - **Context Awareness:** Pass `RoutingContext` or `AuctionContext` as a carrier of state through the chain. + + ### 4.4 Object-Oriented Patterns + - **Value Objects:** Use Lombok `@Value(staticConstructor = "of")` for immutable data carriers. + - **Factory Methods:** Prefer static factory methods named `of(...)` or `create(...)` over public constructors for complex object creation. + - **NoOp Pattern:** For interfaces that may have empty implementations (e.g., hooks, empty services), create a `NoOpExtension` or `static NoOp` implementation within the interface or as a separate class. + - **Sealed Hierarchies:** Use `sealed interface` and `record` (Java 17+) for restricted class hierarchies (e.g., specialized result types). + + ### 4.5 JSON & Serialization + - **JacksonMapper:** Always use the project's `JacksonMapper` wrapper instead of raw `ObjectMapper` where possible. + - **Dynamic JSON:** Use `ObjectNode` and `ArrayNode` for handling dynamic or unstructured data (especially `ext` fields) rather than untyped `Map`. + - **JsonPointer:** Use `JsonPointer` for safe and readable deep traversal of JSON trees (`node.at("/path/to/field")`). +- **Concurrency (Vert.x Core Rule)**: + - **Single Threaded Event Loop**: The application runs on the Event Loop. + - **PROHIBITED**: `synchronized`, `wait()`, `notify()`, `Thread.sleep()`, `BlockingQueue`, or any blocking Java concurrency primitive. + - **Blocking Code**: If you MUST run blocking code (e.g. legacy JDBC), use `vertx.executeBlocking(...)` but prefer non-blocking clients. + - **ALLOWED**: `Future`, `Promise`, `vertx.setTimer()`. +- **Error Handling**: + - **Async**: In async chains, errors propagate automatically. Do not break the chain. + - **Return Failed Future**: In async methods, return `Future.failedFuture(e)` immediately rather than throwing runtime exceptions. + - **Granularity**: Catch specific exceptions in `.recover()`. Avoid broad catches unless it's a top-level handler. +- **Context**: Be aware of the Vert.x `Context`. Ensure context is preserved when switching threads. +- **Logging**: + - Use standard SLF4J usages: `private static final Logger logger = LoggerFactory.getLogger(MyClass.class);` + - Do not use `System.out.println` or `e.printStackTrace()`. + - Log at `DEBUG` for high-volume messages, `INFO` for lifecycle events, `WARN/ERROR` for unexpected conditions. + +## 5. Testing Rules +- **Frameworks**: + - **JUnit 5**: `org.junit.jupiter.api.*`. + - **Behavior Driven Development (BDD)**: Use `given(mock.method()).willReturn(...)` instead of `when(...)`. + - **Strictness**: Use `@Mock(strictness = Mock.Strictness.LENIENT)` for infrastructure mocks (Metrics, Services) defined in `setUp` but not used in every test to avoid `UnnecessaryStubbingException`. + - **Async Testing**: For `Future`-based tests, use `VertxTestContext`: + ```java + @Test + void shouldSucceed(VertxTestContext context) { + future.onComplete(context.succeeding(result -> { + assertThat(result).isNotNull(); + context.completeNow(); + })); + } + ``` + - **Time Testing**: Mock `java.time.Clock` ensures deterministic time tests. + - **Static Imports**: ALWAYS statically import: + - `org.assertj.core.api.Assertions.*` (assertThat, tuple, entry) + - `org.mockito.BDDMockito.*` (given) + - `org.mockito.Mockito.*` (verify, never, etc.) + - `org.mockito.ArgumentMatchers.*` (any, eq, etc.) + - **Assertions**: + - Use `extracting()` for nested properties. + - Use `containsExactlyInAnyOrder` for lists. + - Use `containsOnly` for verifying single-element logical containment. + - **Structure**: + - Use `target` as the name for the class under test instance. + - Use `setUp()` method annotated with `@BeforeEach`. + - **Vert.x Data**: Use `MultiMap.caseInsensitiveMultiMap()` for testing headers/params. + - Fields: SUT (System Under Test) named `target`. +- **Granularity**: + - 1 Test = 1 Logic Path. Avoid `testFooAndBar`. Split into `testFoo` and `testBar`. + - No `ParameterizedTest` preference; explicitly write separate tests for meaningful scenarios (per docs). +- **Data Placement**: + - **Inline Data**: Place test data INSIDE the test method (local variables). + - **No Constants**: Avoid class-level constants for test data. + - **Fake Data**: Do not use real URLs/IDs (use `test.com`, `id`). +- **Mocking**: + - Annotate test class with `@ExtendWith(MockitoExtension.class)`. + - Use `@Mock` for dependencies. + - Use strict mocking (default). Only use `lenientness` if absolutely necessary for shared setup. +- **Naming**: `methodNameShouldReturnExpectedBehaviorWhenCondition`. + - Example: `processDataShouldReturnResultWhenInputIsData`. +- **BDD Style**: + ```java + // given + given(dependency.call()).willReturn(futureResult); + final var input = "test-input"; // 'var' is acceptable in tests only if brevity aids readability, but prefer explicit types per project rule. + + // when + Future result = target.execute(input); + + // then + assertThat(result.succeeded()).isTrue(); + ``` + +## 6. Implementation Workflow (Agent Instructions) +1. **Analyze**: Read existing code and `pom.xml` to understand dependencies. +2. **Plan**: Propose changes before writing. +3. **Implement**: + - Write logic using functional style (`Stream` API). + - Ensure extensive logging for debuggability (at `debug` or `trace` level for high-volume paths). +4. **Test**: + - ALWAYS write or update unit tests for changed logic. + - Validate logic with `VertxTest` if async/JSON is involved. + +## 7. Example Test Template + +```java +package org.prebid.server.component; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.prebid.server.VertxTest; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +class ExampleTest { + + @Mock + private Dependency dependency; + @Mock(strictness = Mock.Strictness.LENIENT) // Common infra mock + private Metrics metrics; + + private Example target; + + @BeforeEach + void setUp() { + target = new Example(dependency, metrics); + } + + @Test + void shouldReturnExpectedValueWhenConditionMet() { + // given + given(dependency.getData()).willReturn("data"); + + // when + final var result = target.process(); + + // then + assertThat(result) + .extracting(Result::getValue) + .isEqualTo("data"); + verify(metrics).updateMetric(any()); + } +} +``` diff --git a/.gemini/settings.json b/.gemini/settings.json new file mode 100644 index 00000000000..44d4be1fc97 --- /dev/null +++ b/.gemini/settings.json @@ -0,0 +1,15 @@ +{ + "hooks": { + "BeforeTool": [ + { + "matcher": "read_file|list_directory", + "hooks": [ + { + "type": "command", + "command": "python -c \"import sys,pathlib,json;e=pathlib.Path('graphify-out/graph.json').exists();d={'decision':'allow'};e and d.update({'additionalContext':'graphify: Knowledge graph exists. Read graphify-out/GRAPH_REPORT.md for god nodes and community structure before searching raw files.'});sys.stdout.write(json.dumps(d))\"" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/.github/workflows/scripts/codepath-notification b/.github/workflows/scripts/codepath-notification index 371c86fc652..7884219ef5b 100644 --- a/.github/workflows/scripts/codepath-notification +++ b/.github/workflows/scripts/codepath-notification @@ -24,3 +24,4 @@ medianet|Medianet: prebid@media.net thetradedesk|TheTradeDesk: Prebid-Maintainers@thetradedesk.com gumgum|GumGum: prebid@gumgum.com kargo|Kargo: kraken@kargo.com +bidwave|Bidwave: prebid@bidwave.net diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 00000000000..f449b672b54 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,9 @@ +## graphify + +This project has a graphify knowledge graph at graphify-out/. + +Rules: +- Before answering architecture or codebase questions, read graphify-out/GRAPH_REPORT.md for god nodes and community structure +- If graphify-out/wiki/index.md exists, navigate it instead of reading raw files +- For cross-module "how does X relate to Y" questions, prefer `graphify query ""`, `graphify path "" ""`, or `graphify explain ""` over grep — these traverse the graph's EXTRACTED + INFERRED edges instead of scanning files +- After modifying code files in this session, run `graphify update .` to keep the graph current (AST-only, no API cost) diff --git a/extra/.vscode_old/launch.json b/extra/.vscode_old/launch.json new file mode 100644 index 00000000000..3641a02708c --- /dev/null +++ b/extra/.vscode_old/launch.json @@ -0,0 +1,36 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Debug Prebid Server (default config)", + "request": "launch", + "mainClass": "org.prebid.server.Application", + "projectName": "prebid-server-bundle", + "args": [ + "--spring.config.additional-location=sample/configs/prebid-config-with-optable.yaml" + ], + "vmArgs": "-Xmx2G -Dlogging.level.root=INFO" + }, + { + "type": "java", + "name": "Debug Prebid Server (custom YAML)", + "request": "launch", + "mainClass": "org.prebid.server.Application", + "projectName": "prebid-server", + "args": [ + "--spring.config.additional-location=config/my-prebid.yaml" + ], + "vmArgs": "-Xmx2G -Dlogging.level.root=DEBUG" + }, + { + "type": "java", + "name": "Debug Prebid Server (no args)", + "request": "launch", + "mainClass": "org.prebid.server.Application", + "projectName": "prebid-server", + "vmArgs": "-Xmx1G" + } + ] + } + \ No newline at end of file diff --git a/extra/.vscode_old/settings.json b/extra/.vscode_old/settings.json new file mode 100644 index 00000000000..6426ceea05a --- /dev/null +++ b/extra/.vscode_old/settings.json @@ -0,0 +1,18 @@ +{ + "java.configuration.maven.pomFile": "extra/pom.xml", + "java.import.maven.enabled": true, + "java.autobuild.enabled": true, + "java.configuration.updateBuildConfiguration": "automatic", + "java.errors.incompleteClasspath.severity": "ignore", + "files.watcherExclude": { + "**/target/**": true + }, + "java.completion.importOrder": [ + "#", + "java" + ], + "editor.codeActionsOnSave": { + "source.organizeImports": "never" + } + } + \ No newline at end of file diff --git a/extra/.vscode_old/tasks.json b/extra/.vscode_old/tasks.json new file mode 100644 index 00000000000..aa0aab32b13 --- /dev/null +++ b/extra/.vscode_old/tasks.json @@ -0,0 +1,33 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Maven: Fetch dependencies", + "type": "shell", + "command": "mvn -q dependency:go-offline", + "group": "build", + "problemMatcher": [] + }, + { + "label": "Maven: Build (full package)", + "type": "shell", + "command": "mvn -q clean package -DskipTests", + "group": "build", + "problemMatcher": "$maven" + }, + { + "label": "Maven: Test", + "type": "shell", + "command": "mvn -q test", + "group": "test", + "problemMatcher": "$maven" + }, + { + "label": "Format Java (Google Style)", + "type": "shell", + "command": "mvn -q spotless:apply", + "problemMatcher": [] + } + ] + } + \ No newline at end of file diff --git a/extra/bundle/README.md b/extra/bundle/README.md index 7909b5d8c87..684c922eca0 100644 --- a/extra/bundle/README.md +++ b/extra/bundle/README.md @@ -1,2 +1,3 @@ # prebid-server-bundle-java + Combines Prebid Server Java and a host company's chosen modules diff --git a/extra/bundle/pom.xml b/extra/bundle/pom.xml index a25d8772e45..432108c863b 100644 --- a/extra/bundle/pom.xml +++ b/extra/bundle/pom.xml @@ -5,7 +5,7 @@ org.prebid prebid-server-aggregator - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT ../../extra/pom.xml diff --git a/extra/modules/confiant-ad-quality/README.md b/extra/modules/confiant-ad-quality/README.md index 50aa6400c64..fa10b97ac7d 100644 --- a/extra/modules/confiant-ad-quality/README.md +++ b/extra/modules/confiant-ad-quality/README.md @@ -5,6 +5,7 @@ This module obtains all bid responses for any given auction, sends the results t ## Configuration To start using current module you have to enable module and add ``confiant-ad-quality-bid-responses-scan-hook`` into hooks execution plan inside your yaml file: + ```yaml hooks: confiant-ad-quality: @@ -32,25 +33,26 @@ hooks: } } ``` + And configure ## List of module configuration options - `api-key` - Confiant's API key. - `redis-config` - - `write-node` - - `host` - Host value of the Confiant's Write Redis Node. - - `port` - Port value of the Confiant's Write Redis Node. - - `password` - User password value of the Confiant's Write Redis Node. - - `read-node` - - `host` - Host value of the Confiant's Read Redis Node. - - `port` - Port value of the Confiant's Read Redis Node. - - `password` - User password value of the Confiant's Read Redis Node. + - `write-node` + - `host` - Host value of the Confiant's Write Redis Node. + - `port` - Port value of the Confiant's Write Redis Node. + - `password` - User password value of the Confiant's Write Redis Node. + - `read-node` + - `host` - Host value of the Confiant's Read Redis Node. + - `port` - Port value of the Confiant's Read Redis Node. + - `password` - User password value of the Confiant's Read Redis Node. - `redis-retry-config` - - `short-interval-attempts` - Maximum attempts with short interval value to try to reconnect to Confiant's Redis server in case any connection error happens. - - `short-interval` - Short time interval in milliseconds after which another one attempt to connect to Redis will be executed. - - `long-interval-attempts` - Maximum attempts with long interval value to try to reconnect to Confiant's Redis server in case any connection error happens. This attempts are used when short-attempts were not successful. - - `long-interval` - Long time interval in milliseconds after which another one attempt to connect to Redis will be executed. + - `short-interval-attempts` - Maximum attempts with short interval value to try to reconnect to Confiant's Redis server in case any connection error happens. + - `short-interval` - Short time interval in milliseconds after which another one attempt to connect to Redis will be executed. + - `long-interval-attempts` - Maximum attempts with long interval value to try to reconnect to Confiant's Redis server in case any connection error happens. This attempts are used when short-attempts were not successful. + - `long-interval` - Long time interval in milliseconds after which another one attempt to connect to Redis will be executed. - `scan-state-check-interval` - Time interval in milliseconds between periodic calls to check if scan state is enabled on the side of Redis server. - `bidders-to-exclude-from-scan` - List of bidders which won't be scanned by Confiant diff --git a/extra/modules/confiant-ad-quality/pom.xml b/extra/modules/confiant-ad-quality/pom.xml index 55466521500..b4a4e783e37 100644 --- a/extra/modules/confiant-ad-quality/pom.xml +++ b/extra/modules/confiant-ad-quality/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT confiant-ad-quality diff --git a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/BidScanResult.java b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/BidScanResult.java index 0a797133ec7..33278dc9c43 100644 --- a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/BidScanResult.java +++ b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/BidScanResult.java @@ -19,7 +19,9 @@ public class BidScanResult { @JsonProperty("tag_key") String tagKey; - /** Impression ID as retrieved in breq.imp.id */ + /** + * Impression ID as retrieved in breq.imp.id + */ @JsonProperty("imp_id") String impId; @@ -30,6 +32,8 @@ public class BidScanResult { @JsonProperty("ro_skipped") boolean roSkipped; - /** An array of issue objects {@link Issue}. Only available if known_creative is true. */ + /** + * An array of issue objects {@link Issue}. Only available if known_creative is true. + */ List issues; } diff --git a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/RedisConfig.java b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/RedisConfig.java index b872dce1776..7818d0008cb 100644 --- a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/RedisConfig.java +++ b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/RedisConfig.java @@ -5,9 +5,13 @@ @Data public class RedisConfig { - /** Redis replica with write access */ + /** + * Redis replica with write access + */ RedisConnectionConfig writeNode; - /** Redis replica with read only access */ + /** + * Redis replica with read only access + */ RedisConnectionConfig readNode; } diff --git a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/RedisConnectionConfig.java b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/RedisConnectionConfig.java index 53c86237b39..1fd76bf6e44 100644 --- a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/RedisConnectionConfig.java +++ b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/model/RedisConnectionConfig.java @@ -5,12 +5,18 @@ @Data public class RedisConnectionConfig { - /** Host value of the Redis server */ + /** + * Host value of the Redis server + */ String host; - /** Port value of the Redis server */ + /** + * Port value of the Redis server + */ int port; - /** User password value of the Redis server */ + /** + * User password value of the Redis server + */ String password; } diff --git a/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsMapperTest.java b/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsMapperTest.java index 3d168eaeedd..a660e06449f 100644 --- a/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsMapperTest.java +++ b/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsMapperTest.java @@ -36,12 +36,12 @@ public void shouldMapBidResponsesToRedisBids() { assertThat(result.getBreq()).isEqualTo(bidRequest); assertThat(result.getBresps()).hasSize(2); - final RedisBidResponseData redisBidResponseData1 = result.getBresps().get(0); + final RedisBidResponseData redisBidResponseData1 = result.getBresps().getFirst(); assertThat(redisBidResponseData1.getDspId()).isEqualTo(bidderResponse1.getBidder()); assertThat(redisBidResponseData1.getBidresponse().getId()).isEqualTo(bidRequest.getId()); - assertThat(redisBidResponseData1.getBidresponse().getCur()).isEqualTo(bidRequest.getCur().get(0)); + assertThat(redisBidResponseData1.getBidresponse().getCur()).isEqualTo(bidRequest.getCur().getFirst()); assertThat(redisBidResponseData1.getBidresponse().getSeatbid()).hasSize(1); - final SeatBid seatBid1 = redisBidResponseData1.getBidresponse().getSeatbid().get(0); + final SeatBid seatBid1 = redisBidResponseData1.getBidresponse().getSeatbid().getFirst(); assertThat(seatBid1.getBid()).hasSize(1); assertThat(seatBid1.getBid().getFirst().getId()) .isEqualTo(bidderResponse1.getSeatBid().getBids().getFirst().getBid().getId()); @@ -49,10 +49,10 @@ public void shouldMapBidResponsesToRedisBids() { final RedisBidResponseData redisBidResponseData2 = result.getBresps().get(1); assertThat(redisBidResponseData2.getDspId()).isEqualTo(bidderResponse2.getBidder()); assertThat(redisBidResponseData2.getBidresponse().getId()).isEqualTo(bidRequest.getId()); - assertThat(redisBidResponseData2.getBidresponse().getCur()).isEqualTo(bidRequest.getCur().get(0)); + assertThat(redisBidResponseData2.getBidresponse().getCur()).isEqualTo(bidRequest.getCur().getFirst()); assertThat(redisBidResponseData2.getBidresponse().getSeatbid()).hasSize(1); - final SeatBid seatBid2 = redisBidResponseData2.getBidresponse().getSeatbid().get(0); + final SeatBid seatBid2 = redisBidResponseData2.getBidresponse().getSeatbid().getFirst(); assertThat(seatBid2.getBid()).hasSize(1); assertThat(seatBid2.getBid().getFirst().getId()) .isEqualTo(bidderResponse2.getSeatBid().getBids().getFirst().getBid().getId()); diff --git a/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScanResultTest.java b/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScanResultTest.java index fd6377f9a18..01ec2b40f4a 100644 --- a/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScanResultTest.java +++ b/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScanResultTest.java @@ -83,9 +83,9 @@ public void shouldProperlyGroupBiddersByIssues() { // then assertThat(groupByIssues.getWithIssues().size()).isEqualTo(1); - assertThat(groupByIssues.getWithIssues().get(0).getBidder()).isEqualTo("critio1"); + assertThat(groupByIssues.getWithIssues().getFirst().getBidder()).isEqualTo("critio1"); assertThat(groupByIssues.getWithoutIssues().size()).isEqualTo(1); - assertThat(groupByIssues.getWithoutIssues().get(0).getBidder()).isEqualTo("critio2"); + assertThat(groupByIssues.getWithoutIssues().getFirst().getBidder()).isEqualTo("critio2"); } @Test diff --git a/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScannerTest.java b/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScannerTest.java index eaedc93e170..8b040cb9bb5 100644 --- a/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScannerTest.java +++ b/extra/modules/confiant-ad-quality/src/test/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScannerTest.java @@ -55,7 +55,7 @@ public void shouldStartRedisVerticle() { bidsScannerTest.start(startFuture); // then - verify(writeRedisNode).start((Promise) any()); + verify(writeRedisNode).start(any()); } @Test() diff --git a/extra/modules/fiftyone-devicedetection/README.md b/extra/modules/fiftyone-devicedetection/README.md index cf6d22d1843..991c80f1d99 100644 --- a/extra/modules/fiftyone-devicedetection/README.md +++ b/extra/modules/fiftyone-devicedetection/README.md @@ -62,22 +62,21 @@ And configure - `account-filter` - `allow-list` - _(list of strings)_ - A list of account IDs that are allowed to use this module. If empty, everyone is allowed. Full-string match is performed (whitespaces and capitalization matter). Defaults to empty. - `data-file` - - `path` - _(string, **REQUIRED**)_ - The full path to the device detection data file. Sample file can be downloaded from [[data repo on GitHub](https://github.com/51Degrees/device-detection-data/blob/main/51Degrees-LiteV4.1.hash)]. - - `make-temp-copy` - _(boolean)_ - If true, the engine will create a temporary copy of the data file rather than using the data file directly. Defaults to false. - - `update` - - `auto` - _(boolean)_ - Enable/Disable auto update. Defaults to enabled. If enabled, the auto update system will automatically download and apply new data files for device detection. - - `on-startup` - _(boolean)_ - Enable/Disable update on startup. Defaults to enabled. If enabled, the auto update system will be used to check for an update before the device detection engine is created. If an update is available, it will be downloaded and applied before the pipeline is built and returned for use so this may take some time. - - `url` - _(string)_ - Configure the engine to use the specified URL when looking for an updated data file. Default is the 51Degrees update URL. - - `license-key` - _(string)_ - Set the license key used when checking for new device detection data files. Defaults to null. - - `watch-file-system` - _(boolean)_ - The DataUpdateService has the ability to watch a file on disk and refresh the engine as soon as that file is updated. This setting enables/disables that feature. Defaults to true. - - `polling-interval` - _(int, seconds)_ - Set the time between checks for a new data file made by the DataUpdateService in seconds. Default = 30 minutes. + - `path` - _(string, **REQUIRED**)_ - The full path to the device detection data file. Sample file can be downloaded from [[data repo on GitHub](https://github.com/51Degrees/device-detection-data/blob/main/51Degrees-LiteV4.1.hash)]. + - `make-temp-copy` - _(boolean)_ - If true, the engine will create a temporary copy of the data file rather than using the data file directly. Defaults to false. + - `update` + - `auto` - _(boolean)_ - Enable/Disable auto update. Defaults to enabled. If enabled, the auto update system will automatically download and apply new data files for device detection. + - `on-startup` - _(boolean)_ - Enable/Disable update on startup. Defaults to enabled. If enabled, the auto update system will be used to check for an update before the device detection engine is created. If an update is available, it will be downloaded and applied before the pipeline is built and returned for use so this may take some time. + - `url` - _(string)_ - Configure the engine to use the specified URL when looking for an updated data file. Default is the 51Degrees update URL. + - `license-key` - _(string)_ - Set the license key used when checking for new device detection data files. Defaults to null. + - `watch-file-system` - _(boolean)_ - The DataUpdateService has the ability to watch a file on disk and refresh the engine as soon as that file is updated. This setting enables/disables that feature. Defaults to true. + - `polling-interval` - _(int, seconds)_ - Set the time between checks for a new data file made by the DataUpdateService in seconds. Default = 30 minutes. - `performance` - - `profile` - _(string)_ - Set the performance profile for the device detection engine. Must be one of: LowMemory, MaxPerformance, HighPerformance, Balanced, BalancedTemp. Defaults to balanced. - - `concurrency` - _(int)_ - Set the expected number of concurrent operations using the engine. This sets the concurrency of the internal caches to avoid excessive locking. Default: 10. - - `difference` - _(int)_ - Set the maximum difference to allow when processing HTTP headers. The meaning of difference depends on the Device Detection API being used. The difference is the difference in hash value between the hash that was found, and the hash that is being searched for. By default this is 0. For more information see [51Degrees documentation](https://51degrees.com/documentation/_device_detection__hash.html). - - `allow-unmatched` - _(boolean)_ - If set to false, a non-matching User-Agent will result in properties without set values. - If set to true, a non-matching User-Agent will cause the 'default profiles' to be returned. This means that properties will always have values (i.e. no need to check .hasValue) but some may be inaccurate. By default, this is false. - - `drift` - _(int)_ - Set the maximum drift to allow when matching hashes. If the drift is exceeded, the result is considered invalid and values will not be returned. By default this is 0. For more information see [51Degrees documentation](https://51degrees.com/documentation/_device_detection__hash.html). + - `profile` - _(string)_ - Set the performance profile for the device detection engine. Must be one of: LowMemory, MaxPerformance, HighPerformance, Balanced, BalancedTemp. Defaults to balanced. + - `concurrency` - _(int)_ - Set the expected number of concurrent operations using the engine. This sets the concurrency of the internal caches to avoid excessive locking. Default: 10. + - `difference` - _(int)_ - Set the maximum difference to allow when processing HTTP headers. The meaning of difference depends on the Device Detection API being used. The difference is the difference in hash value between the hash that was found, and the hash that is being searched for. By default this is 0. For more information see [51Degrees documentation](https://51degrees.com/documentation/_device_detection__hash.html). + - `allow-unmatched` - _(boolean)_ - If set to false, a non-matching User-Agent will result in properties without set values. If set to true, a non-matching User-Agent will cause the 'default profiles' to be returned. This means that properties will always have values (i.e. no need to check .hasValue) but some may be inaccurate. By default, this is false. + - `drift` - _(int)_ - Set the maximum drift to allow when matching hashes. If the drift is exceeded, the result is considered invalid and values will not be returned. By default this is 0. For more information see [51Degrees documentation](https://51degrees.com/documentation/_device_detection__hash.html). ```yaml hooks: diff --git a/extra/modules/fiftyone-devicedetection/pom.xml b/extra/modules/fiftyone-devicedetection/pom.xml index ebbad623041..33ac268c0a1 100644 --- a/extra/modules/fiftyone-devicedetection/pom.xml +++ b/extra/modules/fiftyone-devicedetection/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT fiftyone-devicedetection diff --git a/extra/modules/fiftyone-devicedetection/sample-requests/data.json b/extra/modules/fiftyone-devicedetection/sample-requests/data.json index c87b9876553..271211b0b91 100644 --- a/extra/modules/fiftyone-devicedetection/sample-requests/data.json +++ b/extra/modules/fiftyone-devicedetection/sample-requests/data.json @@ -1,146 +1,116 @@ { - "imp": - [ - { - "ext": - { - "data": - { - "adserver": - { - "name": "gam", - "adslot": "test" - }, - "pbadslot": "test", - "gpid": "test" - }, - "gpid": "test", - "prebid": - { - "bidder": - { - "appnexus": - { - "placement_id": 1, - "use_pmt_rule": false - } - }, - "adunitcode": "25e8ad9f-13a4-4404-ba74-f9eebff0e86c", - "floors": - { - "floorMin": 0.01 - } - } - }, - "id": "2529eeea-813e-4da6-838f-f91c28d64867", - "banner": - { - "topframe": 1, - "format": - [ - { - "w": 728, - "h": 90 - } - ], - "pos": 1 - }, - "bidfloor": 0.01, - "bidfloorcur": "USD" - } - ], - "site": + "imp": [ { - "domain": "test.com", - "publisher": - { - "domain": "test.com", - "id": "1" + "ext": { + "data": { + "adserver": { + "name": "gam", + "adslot": "test" + }, + "pbadslot": "test", + "gpid": "test" }, - "page": "https://www.test.com/" - }, - "device": - { - "ua": "Mozilla/5.0 (Linux; Android 11; SM-G998W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Mobile Safari/537.36" - }, - "id": "fc4670ce-4985-4316-a245-b43c885dc37a", - "test": 1, - "cur": - [ - "USD" - ], - "source": - { - "ext": - { - "schain": - { - "ver": "1.0", - "complete": 1, - "nodes": - [ - { - "asi": "example.com", - "sid": "1234", - "hp": 1 - } - ] + "gpid": "test", + "prebid": { + "bidder": { + "appnexus": { + "placement_id": 1, + "use_pmt_rule": false } + }, + "adunitcode": "25e8ad9f-13a4-4404-ba74-f9eebff0e86c", + "floors": { + "floorMin": 0.01 + } } + }, + "id": "2529eeea-813e-4da6-838f-f91c28d64867", + "banner": { + "topframe": 1, + "format": [ + { + "w": 728, + "h": 90 + } + ], + "pos": 1 + }, + "bidfloor": 0.01, + "bidfloorcur": "USD" + } + ], + "site": { + "domain": "test.com", + "publisher": { + "domain": "test.com", + "id": "1" }, - "ext": - { - "prebid": + "page": "https://www.test.com/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 11; SM-G998W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Mobile Safari/537.36" + }, + "id": "fc4670ce-4985-4316-a245-b43c885dc37a", + "test": 1, + "cur": [ + "USD" + ], + "source": { + "ext": { + "schain": { + "ver": "1.0", + "complete": 1, + "nodes": [ + { + "asi": "example.com", + "sid": "1234", + "hp": 1 + } + ] + } + } + }, + "ext": { + "prebid": { + "cache": { + "bids": { + "returnCreative": true + }, + "vastxml": { + "returnCreative": true + } + }, + "auctiontimestamp": 1698390609882, + "targeting": { + "includewinners": true, + "includebidderkeys": false + }, + "schains": [ { - "cache": - { - "bids": - { - "returnCreative": true - }, - "vastxml": - { - "returnCreative": true - } - }, - "auctiontimestamp": 1698390609882, - "targeting": - { - "includewinners": true, - "includebidderkeys": false - }, - "schains": - [ - { - "bidders": - [ - "appnexus" - ], - "schain": - { - "ver": "1.0", - "complete": 1, - "nodes": - [ - { - "asi": "example.com", - "sid": "1234", - "hp": 1 - } - ] - } - } - ], - "floors": - { - "enabled": false, - "floorMin": 0.01, - "floorMinCur": "USD" - }, - "createtids": false + "bidders": [ + "appnexus" + ], + "schain": { + "ver": "1.0", + "complete": 1, + "nodes": [ + { + "asi": "example.com", + "sid": "1234", + "hp": 1 + } + ] + } } - }, - "user": - {}, - "tmax": 1700 + ], + "floors": { + "enabled": false, + "floorMin": 0.01, + "floorMinCur": "USD" + }, + "createtids": false + } + }, + "user": {}, + "tmax": 1700 } diff --git a/extra/modules/fiftyone-devicedetection/src/main/java/org/prebid/server/hooks/modules/fiftyone/devicedetection/v1/core/PipelineBuilder.java b/extra/modules/fiftyone-devicedetection/src/main/java/org/prebid/server/hooks/modules/fiftyone/devicedetection/v1/core/PipelineBuilder.java index 99bb8de408c..e39c879053f 100644 --- a/extra/modules/fiftyone-devicedetection/src/main/java/org/prebid/server/hooks/modules/fiftyone/devicedetection/v1/core/PipelineBuilder.java +++ b/extra/modules/fiftyone-devicedetection/src/main/java/org/prebid/server/hooks/modules/fiftyone/devicedetection/v1/core/PipelineBuilder.java @@ -7,6 +7,7 @@ import fiftyone.pipeline.engines.services.DataUpdateServiceDefault; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.hooks.modules.fiftyone.devicedetection.model.config.DataFile; import org.prebid.server.hooks.modules.fiftyone.devicedetection.model.config.DataFileUpdate; import org.prebid.server.hooks.modules.fiftyone.devicedetection.model.config.ModuleConfig; @@ -150,7 +151,7 @@ private static void resolvePerformanceProfile( return; } for (Constants.PerformanceProfiles nextProfile : Constants.PerformanceProfiles.values()) { - if (StringUtils.equalsIgnoreCase(nextProfile.name(), profile)) { + if (Strings.CI.equals(nextProfile.name(), profile)) { pipelineBuilder.setPerformanceProfile(nextProfile); return; } diff --git a/extra/modules/fiftyone-devicedetection/src/main/resources/module-config/fiftyone-devicedetection.yaml b/extra/modules/fiftyone-devicedetection/src/main/resources/module-config/fiftyone-devicedetection.yaml index c54ab0d86f8..847102f408c 100644 --- a/extra/modules/fiftyone-devicedetection/src/main/resources/module-config/fiftyone-devicedetection.yaml +++ b/extra/modules/fiftyone-devicedetection/src/main/resources/module-config/fiftyone-devicedetection.yaml @@ -2,7 +2,7 @@ hooks: modules: fiftyone-devicedetection: account-filter: - allow-list: [] # list of strings + allow-list: [ ] # list of strings data-file: path: ~ # string, REQUIRED, download the sample from https://github.com/51Degrees/device-detection-data/blob/main/51Degrees-LiteV4.1.hash or Enterprise from https://51degrees.com/pricing make-temp-copy: ~ # boolean diff --git a/extra/modules/fiftyone-devicedetection/src/test/java/org/prebid/server/hooks/modules/fiftyone/devicedetection/v1/core/DeviceEnricherTest.java b/extra/modules/fiftyone-devicedetection/src/test/java/org/prebid/server/hooks/modules/fiftyone/devicedetection/v1/core/DeviceEnricherTest.java index ad7208e1237..4495710957c 100644 --- a/extra/modules/fiftyone-devicedetection/src/test/java/org/prebid/server/hooks/modules/fiftyone/devicedetection/v1/core/DeviceEnricherTest.java +++ b/extra/modules/fiftyone-devicedetection/src/test/java/org/prebid/server/hooks/modules/fiftyone/devicedetection/v1/core/DeviceEnricherTest.java @@ -236,7 +236,7 @@ public void populateDeviceInfoShouldPassToFlowDataLatestRawHeaderWhenMultiplePre final List> evidenceFragments = evidence.entrySet().stream().toList(); assertThat(evidenceFragments.size()).isEqualTo(1); - assertThat(evidenceFragments.get(0).getValue()).isEqualTo(rawHeaders.get(1).getValue()); + assertThat(evidenceFragments.getFirst().getValue()).isEqualTo(rawHeaders.get(1).getValue()); } @Test diff --git a/extra/modules/greenbids-real-time-data/pom.xml b/extra/modules/greenbids-real-time-data/pom.xml index d9a6e40c3f1..8b58d002a08 100644 --- a/extra/modules/greenbids-real-time-data/pom.xml +++ b/extra/modules/greenbids-real-time-data/pom.xml @@ -4,7 +4,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT greenbids-real-time-data diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationResultCreator.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationResultCreator.java index d93f8343f22..140425bdccd 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationResultCreator.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsInvocationResultCreator.java @@ -39,8 +39,8 @@ public static GreenbidsInvocationResult create(GreenbidsConfig greenbidsConfig, final InvocationAction invocationAction = isExploration ? InvocationAction.no_action : allRejected - ? InvocationAction.reject - : InvocationAction.update; + ? InvocationAction.reject + : InvocationAction.update; final Map ort2ImpExtResultMap = createOrtb2ImpExtForImps( bidRequest, impsBiddersFilterMap, greenbidsId, isExploration); @@ -49,7 +49,7 @@ public static GreenbidsInvocationResult create(GreenbidsConfig greenbidsConfig, } private static boolean isExploration(GreenbidsConfig greenbidsConfig, String greenbidsId) { - final double explorationRate = ObjectUtils.defaultIfNull( + final double explorationRate = ObjectUtils.getIfNull( greenbidsConfig.getExplorationRate(), DEFAULT_EXPLORATION_RATE); final int hashInt = Integer.parseInt(greenbidsId.substring(greenbidsId.length() - 4), 16); diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java index 121c9f6c3a3..4c84da903fb 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/v1/GreenbidsRealTimeDataProcessedAuctionRequestHook.java @@ -11,8 +11,8 @@ import org.prebid.server.analytics.reporter.greenbids.model.ExplorationResult; import org.prebid.server.analytics.reporter.greenbids.model.Ortb2ImpExtResult; import org.prebid.server.auction.model.BidRejectionReason; -import org.prebid.server.auction.model.Rejection; import org.prebid.server.auction.model.ImpRejection; +import org.prebid.server.auction.model.Rejection; import org.prebid.server.exception.PreBidException; import org.prebid.server.hooks.execution.v1.InvocationResultImpl; import org.prebid.server.hooks.execution.v1.analytics.ActivityImpl; diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/FilterServiceTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/FilterServiceTest.java index 0a3ab82b9cd..2ab64888983 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/FilterServiceTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/FilterServiceTest.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; @@ -72,7 +73,7 @@ public void validateOnnxTensorShouldThrowPreBidExceptionWhenOnnxValueIsNotTensor final Double threshold = 0.5; when(onnxModelRunnerMock.runModel(any(String[][].class))).thenReturn(results); - when(results.spliterator()).thenReturn(Arrays.asList(createInvalidOnnxItem()).spliterator()); + when(results.spliterator()).thenReturn(singletonList(createInvalidOnnxItem()).spliterator()); // when & then assertThatThrownBy(() -> target.filterBidders(onnxModelRunnerMock, throttlingMessages, threshold)) @@ -114,7 +115,7 @@ public void filterBiddersShouldThrowPreBidExceptionWhenTensorSizeMismatchOccurs( final Double threshold = 0.5; when(onnxModelRunnerMock.runModel(any(String[][].class))).thenReturn(results); - when(results.spliterator()).thenReturn(Arrays.asList(createOnnxItem()).spliterator()); + when(results.spliterator()).thenReturn(singletonList(createOnnxItem()).spliterator()); when(onnxTensor.getInfo()).thenReturn(tensorInfo); when(tensorInfo.getShape()).thenReturn(new long[]{0}); diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsPayloadUpdaterTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsPayloadUpdaterTest.java index dbc01798d26..838ee2c1995 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsPayloadUpdaterTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/GreenbidsPayloadUpdaterTest.java @@ -10,8 +10,8 @@ import static java.util.function.UnaryOperator.identity; import static org.assertj.core.api.Assertions.assertThat; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.getAppnexusNode; -import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.getPubmaticNode; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.getMagniteNode; +import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.getPubmaticNode; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenBidRequest; import static org.prebid.server.hooks.modules.greenbids.real.time.data.util.TestBidRequestProvider.givenImpExt; diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/ModelCacheTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/ModelCacheTest.java index 5e9d97fe9cd..8f0fda5b9c6 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/ModelCacheTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/ModelCacheTest.java @@ -55,13 +55,10 @@ public class ModelCacheTest { @Mock private ModelCache target; - private Vertx vertx; - @BeforeEach public void setUp() { - vertx = Vertx.vertx(); target = new ModelCache( - storage, GCS_BUCKET_NAME, cache, MODEL_CACHE_KEY_PREFIX, vertx, onnxModelRunnerFactory); + storage, GCS_BUCKET_NAME, cache, MODEL_CACHE_KEY_PREFIX, Vertx.vertx(), onnxModelRunnerFactory); } @Test diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/ThresholdCacheTest.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/ThresholdCacheTest.java index 90a8d521f71..09e021af66b 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/ThresholdCacheTest.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/core/ThresholdCacheTest.java @@ -55,20 +55,17 @@ public class ThresholdCacheTest { @Mock(strictness = LENIENT) private ThrottlingThresholdsFactory throttlingThresholdsFactory; - private Vertx vertx; - private ThresholdCache target; @BeforeEach public void setUp() { - vertx = Vertx.vertx(); target = new ThresholdCache( storage, GCS_BUCKET_NAME, TestBidRequestProvider.MAPPER, cache, THRESHOLD_CACHE_KEY_PREFIX, - vertx, + Vertx.vertx(), throttlingThresholdsFactory); } diff --git a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java index 4a90a45d393..90ac9efe5ce 100644 --- a/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java +++ b/extra/modules/greenbids-real-time-data/src/test/java/org/prebid/server/hooks/modules/greenbids/real/time/data/util/TestBidRequestProvider.java @@ -19,7 +19,8 @@ public class TestBidRequestProvider { public static final ObjectMapper MAPPER = ObjectMapperProvider.mapper(); - private TestBidRequestProvider() { } + private TestBidRequestProvider() { + } public static BidRequest givenBidRequest(UnaryOperator bidRequestCustomizer, List imps) { diff --git a/extra/modules/live-intent-omni-channel-identity/pom.xml b/extra/modules/live-intent-omni-channel-identity/pom.xml index d981e52f7d0..e5c84ba930a 100644 --- a/extra/modules/live-intent-omni-channel-identity/pom.xml +++ b/extra/modules/live-intent-omni-channel-identity/pom.xml @@ -4,7 +4,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT live-intent-omni-channel-identity diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 13e7d48bea8..d9c3073e01e 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -87,9 +87,9 @@ public Future> call(AuctionRequestPayloa return config.getTreatmentRate() > ThreadLocalRandom.current().nextFloat() ? requestIdentities(auctionRequestPayload.bidRequest(), invocationContext.auctionContext()) - .>map(this::update) - .onFailure(throwable -> conditionalLogger.error( - "Failed enrichment: %s".formatted(throwable.getMessage()), logSamplingRate)) + .>map(this::update) + .onFailure(throwable -> conditionalLogger.error( + "Failed enrichment: %s".formatted(throwable.getMessage()), logSamplingRate)) : noAction(); } @@ -262,18 +262,18 @@ private static User updateUser(User user, List resolvedEids) { private List createEidPermissions(String matcher) { return List.of(ExtRequestPrebidDataEidPermissions.builder() - .matcher(matcher) - .inserter(INSERTER) - .bidders(targetBidders.stream().toList()) - .build()); + .matcher(matcher) + .inserter(INSERTER) + .bidders(targetBidders.stream().toList()) + .build()); } private List modifyEidPermissions( List eidPermissions, String matcher) { final List modifiedEidPermissions = eidPermissions.stream() - .map(p -> updateEidPermission(p, matcher)) - .filter(Objects::nonNull) - .toList(); + .map(p -> updateEidPermission(p, matcher)) + .filter(Objects::nonNull) + .toList(); return ListUtils.union(modifiedEidPermissions, createEidPermissions(matcher)); } diff --git a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java index 3b9f905428a..183011978df 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java +++ b/extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java @@ -76,13 +76,12 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest { private LiveIntentOmniChannelIdentityProcessedAuctionRequestHook target; - private Set configuredBidders; - private ExtRequestPrebidDataEidPermissions defaultPermissions; @BeforeEach public void setUp() { - configuredBidders = Set.of("bidder1", "bidder2"); + final Set configuredBidders = Set.of("bidder1", "bidder2"); + given(properties.getRequestTimeoutMs()).willReturn(5L); given(properties.getIdentityResolutionEndpoint()).willReturn("https://test.com/idres"); given(properties.getAuthToken()).willReturn("auth_token"); diff --git a/extra/modules/optable-targeting/README.md b/extra/modules/optable-targeting/README.md index 9e3b76c6446..a59d9dc8a5b 100644 --- a/extra/modules/optable-targeting/README.md +++ b/extra/modules/optable-targeting/README.md @@ -1,4 +1,5 @@ ## Overview + Optable module operates using a DCN backend API. Please contact your account manager to get started. The optable-targeting module enriches an incoming OpenRTB request by adding to the `user.eids` and `user.data` @@ -203,6 +204,7 @@ would result in this nesting in the JSON configuration: | adserver-targeting | no | boolean | false | If set to true - will add the Optable-specific adserver targeting keywords into the PBS response for every `seatbid[].bid[].ext.prebid.targeting` | | timeout | no | integer | none | A soft timeout (in ms) sent as a hint to the Targeting API endpoint to limit the request times to Optable's external tokenizer services | | id-prefix-order | no | string | none | An optional string of comma separated id prefixes that prioritizes and specifies the order in which ids are provided to Targeting API in a query string. F.e. "c,c1,id5" will guarantee that Targeting API will see id=c:...,c1:...,id5:... if these ids are provided. id-prefixes not mentioned in this list will be added in arbitrary order after the priority prefix ids. This affects Targeting API processing logic | +| hid-prefixes | no | string | none | An optional string of comma separated id prefixes that should additionally be sent to the Targeting API as resolver hints in `hid=prefix:value` query parameters. See the section on Resolver Hints (hid) below for more detail. | | enrichment-percentage | no | integer | 100 | Default percentage (0-100) of bid requests per bidder that will receive enrichment data. Set to 100 to enrich all requests, 0 to disable enrichment by default. | | bidder-enrichment-percentages | no | map | none | Per-bidder overrides for `enrichment-percentage`. Keys are bidder names, values are percentages (0-100). F.e. `{"appnexus": 75, "criteo": 0}` enriches 75% of appnexus requests and none for criteo. Bidders not listed in this map fall back to the default `enrichment-percentage` (100% unless overridden). | | enrich-web | no | boolean | true | Whether to enrich web traffic (requests with a `site` object). | @@ -219,7 +221,6 @@ See [Optable documentation](https://docs.optable.co/optable-documentation/dmp/re on identifier types. Targeting API accepts multiple id parameters - and their order may affect the results, thus `id-prefix-order` specifies the order of the ids. - | Identifier Type | OpenRTB field | ID Type Prefix | |--------------------------------------------------------------------------------|-----------------------------------------------------------------------|------------------------------------------| | Email Address | `user.ext.optable.email` | `e:` | @@ -239,8 +240,8 @@ on identifier types. Targeting API accepts multiple id parameters - and their or ### Optable input erasure -**Note**: `user.ext.optable.email`, `.phone`, `.zip`, `.vid` fields will be removed by the module from the original -OpenRTB request before being sent to bidders. +**Note**: `user.ext.optable.email`, `.phone`, `.zip`, `.vid` and `.id5_signature` fields will be removed by the module +from the original OpenRTB request before being sent to bidders. ### Publisher Provided IDs (PPID) Mapping @@ -263,6 +264,52 @@ ppid-mapping: {"id5-sync.com": "c1"} This will lead to id5 ID supplied as `id=c1:...` to the Targeting API. +### Resolver Hints (`hid`) + +In addition to the regular `id=prefix:value` parameters, the module can forward selected identifiers to the Targeting +API as resolver hints using the `hid=prefix:value` query parameter form. The set of prefixes that should be sent as +`hid` is configured via the `hid-prefixes` parameter, which accepts a comma-separated list of prefix names, f.e.: + +```yaml +hid-prefixes: "c, i6" +``` + +## Targeting API Query Attributes + +In addition to the identifier parameters, the module forwards the following attributes as query string parameters to +the Targeting API: + +| Attribute | Source | +|------------------|--------------------------------------------------------------------------------------------------------------------------------------------| +| `gdpr` | `1` if GDPR applies to the request, `0` otherwise. | +| `gdpr_consent` | TCF consent string, sent when available and the consent is valid. | +| `gpp` | GPP string, sent when available in the resolved GPP context. | +| `gpp_sid` | Comma-separated list of active GPP section IDs (limited to the first two), sent when the set is non-empty. | +| `timeout` | Soft timeout hint (in ms, suffixed with `ms`), sent when the module-level `timeout` property is configured. | +| `osdk` | Always set to `prebid-server`, identifying the caller. | +| `bundle` | App bundle identifier, URL-encoded. Sent when the incoming request has an `app` object (`request.app.bundle`) and the bundle is non-empty. | +| `ver` | App version, URL-encoded. Sent only when `bundle` is non-empty and `request.app.ver` is present and non-empty. | +| `id5_signature` | ID5 signature, URL-encoded. Sent when the resolved `user.ext.optable.id5_signature` is present in the incoming request | + +### App bundle and version + +For app traffic (requests with an `app` object) the module forwards the application's bundle identifier as the +`bundle=` query parameter and, when available, its version as `ver=`. Both values are URL-encoded. The `ver` parameter +is only sent when `bundle` is present and non-empty; requests with a version but no bundle will not produce either +parameter. + +### ID5 signature + +The ID5 signature is propagated to the Targeting API in two ways: + +1. **Request-side signature**: when the incoming OpenRTB request carries `user.ext.optable.id5_signature`, that value + is sent to the Targeting API as the `id5_signature=` query parameter. +2. **Response-side signature**: when the Targeting API response contains refs with an ID5 signature, the module + resolves the signature through the matching optable-eid and propagates it back into the request context, where it + is later injected into the bid response (`ext.prebid.passthrough.optable.id5_signature`) for downstream use. + +The `id5_signature` field is also part of the Optable input erasure, see above. + ## Analytics Tags The following 2 analytics tags are written by the module: @@ -270,7 +317,7 @@ The following 2 analytics tags are written by the module: * `optable-enrich-request` * `optable-enrich-response` -The `status` is either `success` or `failure`. Where it is `failure` a `results[0].value.reason` is provided. +The `status` is either `success` or `failure`. Where it is `failure` a `results[0].value.reason` is provided. For the `optable-enrich-request` activity the `execution-time` value is logged. Example: diff --git a/extra/modules/optable-targeting/pom.xml b/extra/modules/optable-targeting/pom.xml index 644829188ed..0ef3cfb5a59 100644 --- a/extra/modules/optable-targeting/pom.xml +++ b/extra/modules/optable-targeting/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT optable-targeting diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/config/OptableTargetingConfig.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/config/OptableTargetingConfig.java index cc05cfe2a02..ef36467d2b5 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/config/OptableTargetingConfig.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/config/OptableTargetingConfig.java @@ -48,7 +48,7 @@ OptableTargetingProperties optableTargetingProperties() { @Bean IdsMapper queryParametersExtractor(@Value("${logging.sampling-rate:0.01}") double logSamplingRate) { - return new IdsMapper(ObjectMapperProvider.mapper(), logSamplingRate); + return new IdsMapper(logSamplingRate); } @Bean @@ -98,10 +98,11 @@ ConfigResolver configResolver(JsonMerger jsonMerger, OptableTargetingProperties @Bean TargetingRequestExecutor targetingRequestExecutor(OptableTargeting optableTargeting, - UserFpdActivityMask userFpdActivityMask, - TimeoutFactory timeoutFactory) { + UserFpdActivityMask userFpdActivityMask, + TimeoutFactory timeoutFactory, + @Value("${logging.sampling-rate:0.01}") double logSamplingRate) { - return new TargetingRequestExecutor(optableTargeting, userFpdActivityMask, timeoutFactory); + return new TargetingRequestExecutor(optableTargeting, userFpdActivityMask, timeoutFactory, logSamplingRate); } @Bean diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/App.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/App.java new file mode 100644 index 00000000000..1b1cdb51c63 --- /dev/null +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/App.java @@ -0,0 +1,11 @@ +package org.prebid.server.hooks.modules.optable.targeting.model; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class App { + + String bundle; + + String ver; +} diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/ModuleContext.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/ModuleContext.java index 5574a7a72d8..ac7e30eec8d 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/ModuleContext.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/ModuleContext.java @@ -35,6 +35,8 @@ public class ModuleContext { private boolean shouldSkipEnrichment; + private String id5Signature; + public static ModuleContext of(AuctionInvocationContext invocationContext) { final ModuleContext moduleContext = (ModuleContext) invocationContext.moduleContext(); return moduleContext != null ? moduleContext : new ModuleContext(); diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/OptableAttributes.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/OptableAttributes.java index 9dacd6de322..d53d1963795 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/OptableAttributes.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/OptableAttributes.java @@ -23,4 +23,8 @@ public class OptableAttributes { String userAgent; Long timeout; + + App app; + + String id5Signature; } diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/Query.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/Query.java index 20862050f39..9b24ed2ed9d 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/Query.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/Query.java @@ -7,9 +7,13 @@ public class Query { String ids; + String hid; + String attributes; + String hidAttributes; + public String toQueryString() { - return ids + attributes; + return ids + hid + attributes + hidAttributes; } } diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/config/OptableTargetingProperties.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/config/OptableTargetingProperties.java index 15ed1d2012b..314e2639cef 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/config/OptableTargetingProperties.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/config/OptableTargetingProperties.java @@ -32,6 +32,9 @@ public final class OptableTargetingProperties { @JsonProperty("id-prefix-order") String idPrefixOrder; + @JsonProperty("hid-prefixes") + String hidPrefixes; + @JsonProperty("optable-inserter-eids-merge") Set optableInserterEidsMerge = Set.of(); diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/openrtb/ExtUserOptable.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/openrtb/ExtUserOptable.java index 787b3adbf1a..a0c8f974b69 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/openrtb/ExtUserOptable.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/openrtb/ExtUserOptable.java @@ -17,4 +17,6 @@ public class ExtUserOptable extends FlexibleExtension { String zip; String vid; + + String id5Signature; } diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/openrtb/TargetingResult.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/openrtb/TargetingResult.java index 826ce2698ed..5bc11a92bd3 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/openrtb/TargetingResult.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/openrtb/TargetingResult.java @@ -1,5 +1,6 @@ package org.prebid.server.hooks.modules.optable.targeting.model.openrtb; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Value; import java.util.List; @@ -10,4 +11,6 @@ public class TargetingResult { List audience; Ortb2 ortb2; + + ObjectNode refs; } diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableBidderRequestHook.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableBidderRequestHook.java index b5ce4cd7531..317cb621fe4 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableBidderRequestHook.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableBidderRequestHook.java @@ -10,6 +10,7 @@ import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.TargetingResult; import org.prebid.server.hooks.modules.optable.targeting.v1.core.AnalyticTagsResolver; import org.prebid.server.hooks.modules.optable.targeting.v1.core.BidderRequestEnricher; +import org.prebid.server.hooks.modules.optable.targeting.v1.core.Id5Resolver; import org.prebid.server.hooks.v1.InvocationAction; import org.prebid.server.hooks.v1.InvocationResult; import org.prebid.server.hooks.v1.InvocationStatus; @@ -58,6 +59,7 @@ private Future> enrichedPayload(Targeting if (hasData) { moduleContext.setTargeting(targetingResult.getAudience()); + moduleContext.setId5Signature(Id5Resolver.resolveId5Signature(targetingResult)); moduleContext.setEnrichRequestStatus(EnrichmentStatus.success()); } @@ -94,7 +96,9 @@ private static long calcExecutionTime(ModuleContext moduleContext) { return startTime > 0 ? System.currentTimeMillis() - startTime : 0; } - private Future> noAction(ModuleContext moduleContext, Tags analyticsTags) { + private Future> noAction(ModuleContext moduleContext, + Tags analyticsTags) { + return Future.succeededFuture( InvocationResultImpl.builder() .status(InvocationStatus.success) diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingAuctionResponseHook.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingAuctionResponseHook.java index 8edef6b00eb..5b915618b0c 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingAuctionResponseHook.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingAuctionResponseHook.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.vertx.core.Future; -import org.apache.commons.collections4.CollectionUtils; import org.prebid.server.hooks.execution.v1.InvocationResultImpl; import org.prebid.server.hooks.modules.optable.targeting.model.EnrichmentStatus; import org.prebid.server.hooks.modules.optable.targeting.model.ModuleContext; @@ -13,6 +12,7 @@ import org.prebid.server.hooks.modules.optable.targeting.v1.core.AuctionResponseValidator; import org.prebid.server.hooks.modules.optable.targeting.v1.core.BidResponseEnricher; import org.prebid.server.hooks.modules.optable.targeting.v1.core.ConfigResolver; +import org.prebid.server.hooks.modules.optable.targeting.v1.core.Id5SignatureBidResponseEnricher; import org.prebid.server.hooks.v1.InvocationAction; import org.prebid.server.hooks.v1.InvocationResult; import org.prebid.server.hooks.v1.InvocationStatus; @@ -53,26 +53,38 @@ public Future> call(AuctionResponsePayl moduleContext.setAdserverTargetingEnabled(adserverTargeting); if (moduleContext.isShouldSkipEnrichment() || !adserverTargeting) { - return success(moduleContext); + return id5SignatureOnlyPayload(moduleContext); } + final List targeting = moduleContext.getTargeting(); + final EnrichmentStatus validationStatus = AuctionResponseValidator.checkEnrichmentPossibility( - auctionResponsePayload.bidResponse(), moduleContext.getTargeting()); + auctionResponsePayload.bidResponse(), targeting); moduleContext.setEnrichResponseStatus(validationStatus); return validationStatus.getStatus() == Status.SUCCESS - ? enrichedPayload(moduleContext) - : success(moduleContext); + ? update(fullEnrichmentChain(targeting, moduleContext.getId5Signature()), moduleContext) + : id5SignatureOnlyPayload(moduleContext); } - private Future> enrichedPayload(ModuleContext moduleContext) { - final List targeting = moduleContext.getTargeting(); + private PayloadUpdate fullEnrichmentChain(final List targeting, + final String id5Signature) { - return CollectionUtils.isNotEmpty(targeting) - ? update(BidResponseEnricher.of(targeting, objectMapper, jsonMerger), moduleContext) + return BidResponseEnricher.of(targeting, objectMapper, jsonMerger) + .andThen(Id5SignatureBidResponseEnricher.of(id5Signature, objectMapper, jsonMerger))::apply; + } + + private Future> id5SignatureOnlyPayload(ModuleContext moduleContext) { + final String id5Signature = moduleContext.getId5Signature(); + return id5Signature != null + ? update(id5SignatureEnrichmentChain(id5Signature), moduleContext) : success(moduleContext); } + private PayloadUpdate id5SignatureEnrichmentChain(String id5Signature) { + return Id5SignatureBidResponseEnricher.of(id5Signature, objectMapper, jsonMerger); + } + private Future> update( PayloadUpdate payloadUpdate, ModuleContext moduleContext) { diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHook.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHook.java index dfa8520f157..fc22fdc354c 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHook.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHook.java @@ -11,8 +11,9 @@ import org.prebid.server.hooks.modules.optable.targeting.v1.core.BidRequestEnricher; import org.prebid.server.hooks.modules.optable.targeting.v1.core.CompositeHookExecutionPlan; import org.prebid.server.hooks.modules.optable.targeting.v1.core.ConfigResolver; -import org.prebid.server.hooks.modules.optable.targeting.v1.core.TargetingRequestExecutor; +import org.prebid.server.hooks.modules.optable.targeting.v1.core.Id5Resolver; import org.prebid.server.hooks.modules.optable.targeting.v1.core.PropertiesValidator; +import org.prebid.server.hooks.modules.optable.targeting.v1.core.TargetingRequestExecutor; import org.prebid.server.hooks.v1.InvocationAction; import org.prebid.server.hooks.v1.InvocationResult; import org.prebid.server.hooks.v1.InvocationStatus; @@ -105,6 +106,7 @@ private Future> enrichPayload( OptableTargetingProperties properties) { moduleContext.setTargeting(targetingResult.getAudience()); + moduleContext.setId5Signature(Id5Resolver.resolveId5Signature(targetingResult)); moduleContext.setEnrichRequestStatus(EnrichmentStatus.success()); final PayloadUpdate payloadUpdate = diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestCleaner.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestCleaner.java index 30652383942..d467e6df750 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestCleaner.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestCleaner.java @@ -14,7 +14,7 @@ public class BidRequestCleaner implements PayloadUpdate { private static final String OPTABLE_FIELD = "optable"; - private static final List FIELDS_TO_REMOVE = List.of("email", "phone", "zip", "vid"); + private static final List FIELDS_TO_REMOVE = List.of("email", "phone", "zip", "vid", "id5_signature"); public static BidRequestCleaner instance() { return new BidRequestCleaner(); diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/ExtUserOptableResolver.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/ExtUserOptableResolver.java new file mode 100644 index 00000000000..1d7e081148e --- /dev/null +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/ExtUserOptableResolver.java @@ -0,0 +1,26 @@ +package org.prebid.server.hooks.modules.optable.targeting.v1.core; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.ExtUserOptable; +import org.prebid.server.json.ObjectMapperProvider; +import org.prebid.server.log.ConditionalLogger; +import org.prebid.server.log.LoggerFactory; + +public class ExtUserOptableResolver { + + private static final ConditionalLogger conditionalLogger = + new ConditionalLogger(LoggerFactory.getLogger(ExtUserOptableResolver.class)); + + private ExtUserOptableResolver() { + } + + public static ExtUserOptable resolveExtUserOptable(JsonNode node, double logSamplingRate) { + try { + return ObjectMapperProvider.mapper().treeToValue(node, ExtUserOptable.class); + } catch (JsonProcessingException e) { + conditionalLogger.warn("Can't parse $.ext.user.Optable tag", logSamplingRate); + return null; + } + } +} diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5Resolver.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5Resolver.java new file mode 100644 index 00000000000..4349ad21240 --- /dev/null +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5Resolver.java @@ -0,0 +1,74 @@ +package org.prebid.server.hooks.modules.optable.targeting.v1.core; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.Eid; +import com.iab.openrtb.request.Uid; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.Ortb2; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.TargetingResult; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.User; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class Id5Resolver { + + public static final String OPTABLE_INSERTER = "optable.co"; + public static final String ID5_SOURCE = "id5-sync.com"; + public static final String OPTABLE = "optable"; + public static final String REF = "ref"; + public static final String SIGNATURE = "signature"; + + private Id5Resolver() { + } + + public static String resolveId5Signature(TargetingResult targetingResult) { + if (targetingResult == null) { + return null; + } + + final List refs = Optional.of(targetingResult) + .map(TargetingResult::getOrtb2) + .map(Ortb2::getUser) + .map(User::getEids) + .orElseGet(List::of) + .stream() + .filter(it -> OPTABLE_INSERTER.equals(it.getInserter()) && ID5_SOURCE.equals(it.getSource())) + .map(Eid::getUids) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .map(Uid::getExt) + .filter(Objects::nonNull) + .map(it -> it.get(OPTABLE)) + .filter(Objects::nonNull) + .map(it -> it.get(REF)) + .filter(Objects::nonNull) + .map(JsonNode::asText) + .toList(); + + if (CollectionUtils.isEmpty(refs)) { + return null; + } + + final ObjectNode references = targetingResult.getRefs(); + if (references == null) { + return null; + } + + return refs.stream() + .map(references::get) + .filter(Objects::nonNull) + .map(it -> it.get(SIGNATURE)) + .filter(Objects::nonNull) + .filter(JsonNode::isValueNode) + .filter(it -> !it.isNull()) + .map(JsonNode::asText) + .filter(StringUtils::isNotBlank) + .findFirst() + .orElse(null); + } +} diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5SignatureBidResponseEnricher.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5SignatureBidResponseEnricher.java new file mode 100644 index 00000000000..e94af71928d --- /dev/null +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5SignatureBidResponseEnricher.java @@ -0,0 +1,83 @@ +package org.prebid.server.hooks.modules.optable.targeting.v1.core; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import com.iab.openrtb.response.BidResponse; +import org.apache.commons.lang3.StringUtils; +import org.prebid.server.hooks.execution.v1.auction.AuctionResponsePayloadImpl; +import org.prebid.server.hooks.v1.PayloadUpdate; +import org.prebid.server.hooks.v1.auction.AuctionResponsePayload; +import org.prebid.server.json.JsonMerger; +import org.prebid.server.proto.openrtb.ext.response.ExtBidResponse; +import org.prebid.server.proto.openrtb.ext.response.ExtBidResponsePrebid; + +import java.util.Objects; + +public class Id5SignatureBidResponseEnricher implements PayloadUpdate { + + private final String id5Signature; + private final ObjectMapper mapper; + private final JsonMerger jsonMerger; + + private Id5SignatureBidResponseEnricher(String id5Signature, ObjectMapper mapper, JsonMerger jsonMerger) { + this.id5Signature = id5Signature; + this.mapper = Objects.requireNonNull(mapper); + this.jsonMerger = Objects.requireNonNull(jsonMerger); + } + + public static Id5SignatureBidResponseEnricher of(String id5Signature, ObjectMapper mapper, JsonMerger jsonMerger) { + return new Id5SignatureBidResponseEnricher(id5Signature, mapper, jsonMerger); + } + + @Override + public AuctionResponsePayload apply(AuctionResponsePayload payload) { + return AuctionResponsePayloadImpl.of(enrichBidResponse(payload.bidResponse(), id5Signature)); + } + + private BidResponse enrichBidResponse(BidResponse bidResponse, String id5Signature) { + if (StringUtils.isEmpty(id5Signature)) { + return bidResponse; + } + final ObjectNode passthroughNode = id5SignatureToObjectNode(id5Signature); + + final ExtBidResponse existingExt = bidResponse.getExt(); + final ExtBidResponsePrebid existingPrebid = existingExt != null ? existingExt.getPrebid() : null; + final JsonNode existingPassthrough = existingPrebid != null ? existingPrebid.getPassthrough() : null; + + final JsonNode mergedPassthrough = existingPassthrough != null + ? jsonMerger.merge(passthroughNode, existingPassthrough) + : passthroughNode; + + final ExtBidResponsePrebid modifiedPrebid = existingPrebid != null + ? existingPrebid.toBuilder() + .passthrough(mergedPassthrough) + .build() + : ExtBidResponsePrebid.builder() + .passthrough(mergedPassthrough) + .build(); + + final ExtBidResponse modifiedExt = existingExt != null + ? existingExt.toBuilder() + .prebid(modifiedPrebid) + .build() + : ExtBidResponse.builder() + .prebid(modifiedPrebid) + .build(); + + return bidResponse.toBuilder() + .ext(modifiedExt) + .build(); + } + + private ObjectNode id5SignatureToObjectNode(String id5Signature) { + final ObjectNode node = mapper.createObjectNode(); + node.set("id5_signature", TextNode.valueOf(id5Signature)); + + final ObjectNode optableNode = mapper.createObjectNode(); + optableNode.set("optable", node); + + return optableNode; + } +} diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/IdsMapper.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/IdsMapper.java index 7214f6ce6a3..2ea248334b3 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/IdsMapper.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/IdsMapper.java @@ -1,8 +1,5 @@ package org.prebid.server.hooks.modules.optable.targeting.v1.core; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; import com.iab.openrtb.request.Eid; @@ -14,8 +11,6 @@ import org.prebid.server.hooks.modules.optable.targeting.model.Id; import org.prebid.server.hooks.modules.optable.targeting.model.OS; import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.ExtUserOptable; -import org.prebid.server.log.ConditionalLogger; -import org.prebid.server.log.LoggerFactory; import java.util.Collections; import java.util.HashMap; @@ -26,19 +21,14 @@ public class IdsMapper { - private static final ConditionalLogger conditionalLogger = - new ConditionalLogger(LoggerFactory.getLogger(IdsMapper.class)); - private static final Map STATIC_PPID_MAPPING = Map.of( "id5-sync.com", Id.ID5, "utiq.com", Id.UTIQ, "netid.de", Id.NET_ID); - private final ObjectMapper objectMapper; private final double logSamplingRate; - public IdsMapper(ObjectMapper objectMapper, double logSamplingRate) { - this.objectMapper = Objects.requireNonNull(objectMapper); + public IdsMapper(double logSamplingRate) { this.logSamplingRate = logSamplingRate; } @@ -60,7 +50,7 @@ private void addOptableIds(Map ids, User user) { final Optional extUserOptable = Optional.ofNullable(user) .map(User::getExt) .map(ext -> ext.getProperty("optable")) - .map(this::parseExtUserOptable); + .map(it -> ExtUserOptableResolver.resolveExtUserOptable(it, logSamplingRate)); extUserOptable.map(ExtUserOptable::getEmail).ifPresent(it -> ids.put(Id.EMAIL, it)); extUserOptable.map(ExtUserOptable::getPhone).ifPresent(it -> ids.put(Id.PHONE, it)); @@ -68,19 +58,15 @@ private void addOptableIds(Map ids, User user) { extUserOptable.map(ExtUserOptable::getVid).ifPresent(it -> ids.put(Id.OPTABLE_VID, it)); } - private ExtUserOptable parseExtUserOptable(JsonNode node) { - try { - return objectMapper.treeToValue(node, ExtUserOptable.class); - } catch (JsonProcessingException e) { - conditionalLogger.warn("Can't parse $.ext.user.Optable tag", logSamplingRate); - return null; - } - } - private static void addDeviceIds(Map ids, Device device) { final String ifa = device != null ? device.getIfa() : null; final String os = device != null ? StringUtils.toRootLowerCase(device.getOs()) : null; final int lmt = Optional.ofNullable(device).map(Device::getLmt).orElse(0); + final String ip6 = device != null ? device.getIpv6() : null; + + if (ip6 != null) { + ids.put(Id.DEVICE_IP_V_6, ip6); + } if (ifa == null || StringUtils.isEmpty(os) || lmt == 1) { return; diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolver.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolver.java index 8009a9f2ff5..0828adea34d 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolver.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolver.java @@ -8,7 +8,9 @@ import org.apache.commons.lang3.StringUtils; import org.prebid.server.auction.gpp.model.GppContext; import org.prebid.server.auction.model.AuctionContext; +import org.prebid.server.hooks.modules.optable.targeting.model.App; import org.prebid.server.hooks.modules.optable.targeting.model.OptableAttributes; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.ExtUserOptable; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; import org.prebid.server.proto.openrtb.ext.request.ExtUser; @@ -21,7 +23,10 @@ public class OptableAttributesResolver { private OptableAttributesResolver() { } - public static OptableAttributes resolveAttributes(AuctionContext auctionContext, Long timeout) { + public static OptableAttributes resolveAttributes(AuctionContext auctionContext, + Long timeout, + double logSamplingRate) { + final GppContext.Scope gppScope = auctionContext.getGppContext().scope(); final BidRequest bidRequest = auctionContext.getBidRequest(); @@ -35,6 +40,7 @@ public static OptableAttributes resolveAttributes(AuctionContext auctionContext, final OptableAttributes.OptableAttributesBuilder builder = OptableAttributes.builder() .ips(resolveIp(auctionContext)) .userAgent(resolveUserAgent(auctionContext)) + .app(resolveApp(auctionContext)) .timeout(timeout); if (gdpr != null && gdpr > 0) { @@ -51,15 +57,28 @@ public static OptableAttributes resolveAttributes(AuctionContext auctionContext, } } - if (gppScope.getGppModel() != null) { + if (gppScope != null && gppScope.getGppModel() != null) { builder .gpp(gppScope.getGppModel().encode()) .gppSid(SetUtils.emptyIfNull(gppScope.getSectionsIds())); } + Optional.ofNullable(bidRequest.getUser()) + .map(User::getExt) + .map(ext -> ext.getProperty("optable")) + .map(it -> ExtUserOptableResolver.resolveExtUserOptable(it, logSamplingRate)) + .map(ExtUserOptable::getId5Signature) + .filter(StringUtils::isNotBlank) + .ifPresent(builder::id5Signature); + return builder.build(); } + private static App resolveApp(AuctionContext auctionContext) { + final com.iab.openrtb.request.App app = auctionContext.getBidRequest().getApp(); + return app != null ? App.of(app.getBundle(), app.getVer()) : null; + } + public static String resolveUserAgent(AuctionContext auctionContext) { final Device device = auctionContext.getBidRequest().getDevice(); return device != null ? device.getUa() : null; diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableTargeting.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableTargeting.java index 0cb16d9c456..b79ca2790f2 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableTargeting.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableTargeting.java @@ -29,7 +29,7 @@ public Future getTargeting(OptableTargetingProperties propertie Timeout timeout) { final List ids = idsMapper.toIds(bidRequest, properties.getPpidMapping()); - final Query query = QueryBuilder.build(ids, attributes, properties.getIdPrefixOrder()); + final Query query = QueryBuilder.build(ids, attributes, properties); if (query == null) { return Future.failedFuture("Can't get targeting"); } diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/QueryBuilder.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/QueryBuilder.java index bee89818b2f..78d362d9fec 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/QueryBuilder.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/QueryBuilder.java @@ -5,14 +5,17 @@ import org.prebid.server.hooks.modules.optable.targeting.model.Id; import org.prebid.server.hooks.modules.optable.targeting.model.OptableAttributes; import org.prebid.server.hooks.modules.optable.targeting.model.Query; +import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; @@ -26,12 +29,42 @@ public class QueryBuilder { private QueryBuilder() { } - public static Query build(List ids, OptableAttributes optableAttributes, String idPrefixOrder) { + public static Query build(List ids, OptableAttributes optableAttributes, + OptableTargetingProperties properties) { + if (CollectionUtils.isEmpty(ids) && CollectionUtils.isEmpty(optableAttributes.getIps())) { return null; } - return Query.of(buildIdsString(ids, idPrefixOrder), buildAttributesString(optableAttributes)); + final String idPrefixOrder = properties.getIdPrefixOrder(); + final String hidPrefixes = properties.getHidPrefixes(); + return Query.of( + buildIdsString(ids, idPrefixOrder), + buildHidString(ids, hidPrefixes), + buildAttributesString(optableAttributes), + buildHidAttributesString(optableAttributes)); + } + + private static String buildHidString(List ids, String hidPrefixesString) { + if (CollectionUtils.isEmpty(ids) || StringUtils.isEmpty(hidPrefixesString)) { + return StringUtils.EMPTY; + } + final Map prefixToIdValue = ids.stream() + .collect(Collectors.toMap(Id::getName, it -> it, (a, b) -> b)); + + final String hidParameters = Arrays.stream(hidPrefixesString.split(",")) + .map(String::trim) + .filter(StringUtils::isNotEmpty) + .map(prefixToIdValue::get) + .filter(Objects::nonNull) + .map(it -> String.format( + "hid=%s:%s", it.getName(), URLEncoder.encode(it.getValue(), StandardCharsets.UTF_8))) + .collect(Collectors.joining("&")); + if (StringUtils.isEmpty(hidParameters)) { + return StringUtils.EMPTY; + } + + return "&" + hidParameters; } private static String buildIdsString(List ids, String idPrefixOrder) { @@ -39,14 +72,15 @@ private static String buildIdsString(List ids, String idPrefixOrder) { return StringUtils.EMPTY; } - final List reorderedIds = reorderIds(ids, idPrefixOrder); + final List reorderedIds = reorderIds(ids, idPrefixOrder) + .stream() + .filter(id -> !Id.DEVICE_IP_V_6.equals(id.getName())) + .toList(); final StringBuilder sb = new StringBuilder(); for (Id id : reorderedIds) { sb.append("&id="); - sb.append(URLEncoder.encode( - "%s:%s".formatted(id.getName(), id.getValue()), - StandardCharsets.UTF_8)); + sb.append(URLEncoder.encode(String.format("%s:%s", id.getName(), id.getValue()), StandardCharsets.UTF_8)); } return sb.toString(); @@ -88,4 +122,31 @@ private static String buildAttributesString(OptableAttributes optableAttributes) return sb.toString(); } + + /** + * Kept apart from buildAttributesString because these are the only attributes that + * discriminate one user from another, so they have to take part in the cache key. + */ + private static String buildHidAttributesString(OptableAttributes optableAttributes) { + final StringBuilder sb = new StringBuilder(); + + Optional.ofNullable(optableAttributes.getApp()) + .ifPresent(app -> { + final String bundle = app.getBundle(); + if (StringUtils.isNotEmpty(bundle)) { + sb.append("&bundle=").append(URLEncoder.encode(bundle, StandardCharsets.UTF_8)); + + final String ver = app.getVer(); + if (StringUtils.isNotEmpty(ver)) { + sb.append("&ver=").append(URLEncoder.encode(ver, StandardCharsets.UTF_8)); + } + } + }); + + Optional.ofNullable(optableAttributes.getId5Signature()) + .ifPresent(id5Signature -> sb.append("&id5_signature=") + .append(URLEncoder.encode(id5Signature, StandardCharsets.UTF_8))); + + return sb.toString(); + } } diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/TargetingRequestExecutor.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/TargetingRequestExecutor.java index 36cd33c7724..8a93df9fbdf 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/TargetingRequestExecutor.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/TargetingRequestExecutor.java @@ -29,14 +29,17 @@ public class TargetingRequestExecutor { private final OptableTargeting optableTargeting; private final UserFpdActivityMask userFpdActivityMask; private final TimeoutFactory timeoutFactory; + private final double logSamplingRate; public TargetingRequestExecutor(OptableTargeting optableTargeting, - UserFpdActivityMask userFpdActivityMask, - TimeoutFactory timeoutFactory) { + UserFpdActivityMask userFpdActivityMask, + TimeoutFactory timeoutFactory, + double logSamplingRate) { this.optableTargeting = Objects.requireNonNull(optableTargeting); this.userFpdActivityMask = Objects.requireNonNull(userFpdActivityMask); this.timeoutFactory = ObjectUtils.requireNonEmpty(timeoutFactory); + this.logSamplingRate = logSamplingRate; } public Future makeRequest(AuctionRequestPayload payload, @@ -51,7 +54,8 @@ public Future makeRequest(AuctionRequestPayload payload, : timeoutFactory.create(getHookTimeout(invocationContext).remaining() + apiTimeout); final OptableAttributes attributes = OptableAttributesResolver.resolveAttributes( invocationContext.auctionContext(), - properties.getTimeout()); + properties.getTimeout(), + logSamplingRate); return optableTargeting.getTargeting(properties, bidRequest, attributes, timeout); } diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/CachedAPIClient.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/CachedAPIClient.java index e7e8bc3e452..ada03ab1528 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/CachedAPIClient.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/CachedAPIClient.java @@ -42,7 +42,7 @@ public Future getTargeting(OptableTargetingProperties propertie return cache.get(createCachingKey(tenant, origin, ips, query, true)) .recover(ignore -> apiClient.getTargeting(properties, query, ips, userAgent, timeout) .recover(throwable -> isCircuitBreakerEnabled - ? Future.succeededFuture(new TargetingResult(null, null)) + ? Future.succeededFuture(new TargetingResult(null, null, null)) : Future.failedFuture(throwable)) .compose(result -> cache.put( createCachingKey(tenant, origin, ips, query, false), @@ -53,12 +53,19 @@ public Future getTargeting(OptableTargetingProperties propertie } private String createCachingKey(String tenant, String origin, List ips, Query query, boolean encodeQuery) { - return "%s:%s:%s:%s".formatted( + return "%s:%s:%s:%s:%s:%s".formatted( tenant, origin, ips.getFirst(), encodeQuery ? URLEncoder.encode(query.getIds(), StandardCharsets.UTF_8) - : query.getIds()); + : query.getIds(), + encodeQuery && query.getHid() != null + ? URLEncoder.encode(query.getHid(), StandardCharsets.UTF_8) + : query.getHid(), + encodeQuery && query.getHidAttributes() != null + ? URLEncoder.encode(query.getHidAttributes(), StandardCharsets.UTF_8) + : query.getHidAttributes() + ); } } diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java index 52143ff9fef..5333ff1fbc8 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java @@ -17,6 +17,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpHeaders; import org.apache.commons.io.IOUtils; @@ -73,6 +74,28 @@ protected ModuleContext givenModuleContext(List audiences) { return moduleContext; } + protected ModuleContext givenModuleContext(List audiences, Future optableTargetingCall) { + final ModuleContext moduleContext = givenModuleContext(audiences); + moduleContext.setOptableTargetingCall(optableTargetingCall); + return moduleContext; + } + + protected Eid givenId5Eid(String refValue) { + final ObjectNode uidExt = mapper.createObjectNode(); + uidExt.set("optable", mapper.createObjectNode().set("ref", TextNode.valueOf(refValue))); + return Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id").ext(uidExt).build())) + .build(); + } + + protected ObjectNode givenRefsObject(String refValue, String signature) { + final ObjectNode refs = mapper.createObjectNode(); + refs.set(refValue, mapper.createObjectNode().set("signature", TextNode.valueOf(signature))); + return refs; + } + protected AuctionContext givenAuctionContext(ActivityInfrastructure activityInfrastructure, Timeout timeout, Account account) { @@ -168,17 +191,22 @@ protected TargetingResult givenTargetingResult() { } protected TargetingResult givenTargetingResult(List eids, List data) { + return givenTargetingResult(eids, data, null); + } + + protected TargetingResult givenTargetingResult(List eids, List data, ObjectNode refs) { return new TargetingResult( List.of(new Audience( "provider", List.of(new AudienceId("id")), "keyspace", 1)), - new Ortb2(new org.prebid.server.hooks.modules.optable.targeting.model.openrtb.User(eids, data))); + new Ortb2(new org.prebid.server.hooks.modules.optable.targeting.model.openrtb.User(eids, data)), + refs); } protected TargetingResult givenEmptyTargetingResult() { - return new TargetingResult(Collections.emptyList(), new Ortb2(null)); + return new TargetingResult(Collections.emptyList(), new Ortb2(null), null); } protected User givenUser() { @@ -226,20 +254,10 @@ protected HttpClientResponse givenFailHttpResponse(int statusCode, String fileNa } protected String givenBodyFromFile(String fileName) { - InputStream inputStream = null; - try { - inputStream = Files.newInputStream(Paths.get("src/test/resources/" + fileName)); + try (InputStream inputStream = Files.newInputStream(Paths.get("src/test/resources/" + fileName))) { return IOUtils.toString(inputStream, StandardCharsets.UTF_8); } catch (IOException e) { return null; - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException e) { - // ignore - } - } } } @@ -273,7 +291,7 @@ protected OptableTargetingProperties givenOptableTargetingProperties(String key, } protected Query givenQuery() { - return Query.of("?que", "ry"); + return Query.of("?que", "r", "y", ""); } protected ObjectNode givenAccountConfig(String key, String tenant, String origin, boolean cacheEnabled) { diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableBidderRequestHookTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableBidderRequestHookTest.java index 2bcce42ac94..5778ac41289 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableBidderRequestHookTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableBidderRequestHookTest.java @@ -1,7 +1,9 @@ package org.prebid.server.hooks.modules.optable.targeting.v1; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Eid; import io.vertx.core.Future; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -14,6 +16,7 @@ import org.prebid.server.hooks.modules.optable.targeting.model.EnrichmentStatus; import org.prebid.server.hooks.modules.optable.targeting.model.ModuleContext; import org.prebid.server.hooks.modules.optable.targeting.model.Status; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.TargetingResult; import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties; import org.prebid.server.hooks.v1.InvocationAction; import org.prebid.server.hooks.v1.InvocationResult; @@ -23,6 +26,7 @@ import org.prebid.server.hooks.v1.bidder.BidderRequestPayload; import java.util.Collections; +import java.util.List; import java.util.Set; import java.util.concurrent.TimeoutException; @@ -74,6 +78,80 @@ public void shouldReturnNoActionWhenPerBidderEnrichmentIsDisabled() { assertThat(result.moduleContext()).isSameAs(moduleContext); } + @Test + public void shouldReturnNoActionWhenPerBidderEnrichmentIsDisabledAndTargetingCallFailed() { + // given + final ModuleContext moduleContext = givenModuleContextWithProperties( + givenOptableTargetingProperties(false)); + moduleContext.setOptableTargetingCall(Future.failedFuture(new RuntimeException("timeout"))); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + // when + final Future> future = + target.call(bidderRequestPayload, invocationContext); + // then + assertThat(future.succeeded()).isTrue(); + final InvocationResult result = future.result(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.no_action, InvocationResult::action); + assertThat(moduleContext.getId5Signature()).isNull(); + } + + @Test + public void shouldNotSetId5SignatureOnModuleContextWhenPerBidderEnrichmentIsDisabledAndTargetingCallIsPresent() { + // given + final String refValue = "refValue"; + final String signature = "id5Signature"; + final Eid id5Eid = givenId5Eid(refValue); + final ObjectNode refs = givenRefsObject(refValue, signature); + final TargetingResult targetingResult = givenTargetingResult(List.of(id5Eid), null, refs); + + final ModuleContext moduleContext = givenModuleContextWithProperties( + givenOptableTargetingProperties(false)); + moduleContext.setOptableTargetingCall(Future.succeededFuture(targetingResult)); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + + // when + final Future> future = + target.call(bidderRequestPayload, invocationContext); + + // then + assertThat(future.succeeded()).isTrue(); + final InvocationResult result = future.result(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.no_action, InvocationResult::action); + assertThat(moduleContext.getId5Signature()).isNull(); + } + + @Test + public void shouldNotSetId5SignatureOnModuleContextWhenBidderNotInEnrichmentSetAndTargetingCallIsPresent() { + // given + final String refValue = "refValue"; + final String signature = "id5Signature"; + final Eid id5Eid = givenId5Eid(refValue); + final ObjectNode refs = givenRefsObject(refValue, signature); + final TargetingResult targetingResult = givenTargetingResult(List.of(id5Eid), null, refs); + + final ModuleContext moduleContext = givenModuleContextWithProperties( + givenPropertiesWithPerBidderEnrichmentEnabled()); + moduleContext.setBiddersToEnrich(Set.of("otherBidder")); + moduleContext.setOptableTargetingCall(Future.succeededFuture(targetingResult)); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + + // when + final Future> future = + target.call(bidderRequestPayload, invocationContext); + + // then + assertThat(future.succeeded()).isTrue(); + final InvocationResult result = future.result(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.no_action, InvocationResult::action); + assertThat(moduleContext.getId5Signature()).isNull(); + } + @Test public void shouldReturnNoActionWhenBiddersToEnrichIsEmpty() { // given @@ -170,6 +248,48 @@ public void shouldUpdateModuleContextWithTargetingOnSuccess() { .isEqualTo("success"); } + @Test + public void shouldSetId5SignatureOnModuleContextWhenTargetingResultHasId5Signature() { + // given + final String refValue = "refValue"; + final String signature = "id5Signature"; + final Eid id5Eid = givenId5Eid(refValue); + final ObjectNode refs = givenRefsObject(refValue, signature); + final TargetingResult targetingResult = givenTargetingResult(List.of(id5Eid), null, refs); + + final ModuleContext moduleContext = givenModuleContextWithProperties( + givenPropertiesWithPerBidderEnrichmentEnabled()); + moduleContext.setBiddersToEnrich(Set.of("bidder1")); + moduleContext.setCallTargetingAPITimestamp(System.currentTimeMillis() - 100); + moduleContext.setOptableTargetingCall(Future.succeededFuture(targetingResult)); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + when(invocationContext.bidder()).thenReturn("bidder1"); + + // when + target.call(bidderRequestPayload, invocationContext); + + // then + assertThat(moduleContext.getId5Signature()).isEqualTo(signature); + } + + @Test + public void shouldNotSetId5SignatureOnModuleContextWhenTargetingResultHasNoId5Signature() { + // given + final ModuleContext moduleContext = givenModuleContextWithProperties( + givenPropertiesWithPerBidderEnrichmentEnabled()); + moduleContext.setBiddersToEnrich(Set.of("bidder1")); + moduleContext.setCallTargetingAPITimestamp(System.currentTimeMillis() - 100); + moduleContext.setOptableTargetingCall(Future.succeededFuture(givenTargetingResult())); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + when(invocationContext.bidder()).thenReturn("bidder1"); + + // when + target.call(bidderRequestPayload, invocationContext); + + // then + assertThat(moduleContext.getId5Signature()).isNull(); + } + @Test public void shouldReturnNoActionWithNoDataOutcomeWhenTargetingResultHasNoUser() { // given diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHookTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHookTest.java index 059db74ce0e..4e1a5b3e5f1 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHookTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHookTest.java @@ -63,7 +63,8 @@ public void setUp() { when(userFpdActivityMask.maskDevice(any(), anyBoolean(), anyBoolean())) .thenAnswer(answer -> answer.getArgument(0)); configResolver = new ConfigResolver(mapper, jsonMerger, givenOptableTargetingProperties(false)); - targetingRequestExecutor = new TargetingRequestExecutor(optableTargeting, userFpdActivityMask, timeoutFactory); + targetingRequestExecutor = new TargetingRequestExecutor( + optableTargeting, userFpdActivityMask, timeoutFactory, 0.01); target = new OptableRawAuctionRequestHook( configResolver, targetingRequestExecutor, bidderEnrichmentSampler, CompositeHookExecutionPlan.of(ExecutionPlan.empty()), 0.01); diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingAuctionResponseHookTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingAuctionResponseHookTest.java index 7d1df51bc5e..a73c0f3fa10 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingAuctionResponseHookTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingAuctionResponseHookTest.java @@ -1,5 +1,6 @@ package org.prebid.server.hooks.modules.optable.targeting.v1; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.response.BidResponse; import io.vertx.core.Future; @@ -10,6 +11,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.hooks.execution.v1.auction.AuctionResponsePayloadImpl; import org.prebid.server.hooks.modules.optable.targeting.model.ModuleContext; +import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties; import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.Audience; import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.AudienceId; import org.prebid.server.hooks.modules.optable.targeting.v1.core.ConfigResolver; @@ -32,7 +34,6 @@ @ExtendWith(MockitoExtension.class) public class OptableTargetingAuctionResponseHookTest extends BaseOptableTest { - private ConfigResolver configResolver; private AuctionResponseHook target; @Mock @@ -43,9 +44,9 @@ public class OptableTargetingAuctionResponseHookTest extends BaseOptableTest { @BeforeEach public void setUp() { when(invocationContext.accountConfig()).thenReturn(givenAccountConfig(true)); - configResolver = new ConfigResolver(mapper, jsonMerger, givenOptableTargetingProperties(false)); + target = new OptableTargetingAuctionResponseHook( - configResolver, + new ConfigResolver(mapper, jsonMerger, givenOptableTargetingProperties(false)), mapper, jsonMerger); } @@ -58,9 +59,10 @@ public void shouldHaveCode() { } @Test - public void shouldReturnResultWithNoActionAndWithPBSAnalyticsTags() { + public void shouldReturnResultWithNoActionAndWithPBSAnalyticsTagsWhenTargetingIsEmptyAndNoId5Signature() { // given - when(invocationContext.moduleContext()).thenReturn(givenModuleContext()); + when(invocationContext.moduleContext()).thenReturn( + givenModuleContext(null, Future.failedFuture(new RuntimeException("error")))); // when final Future> future = @@ -74,6 +76,7 @@ public void shouldReturnResultWithNoActionAndWithPBSAnalyticsTags() { assertThat(result).isNotNull() .returns(InvocationStatus.success, InvocationResult::status) .returns(InvocationAction.no_action, InvocationResult::action); + assertThat(result.payloadUpdate()).isNull(); assertThat(result.analyticsTags()) .extracting(Tags::activities) .extracting(List::getFirst) @@ -85,6 +88,36 @@ public void shouldReturnResultWithNoActionAndWithPBSAnalyticsTags() { assertThat(result.errors()).isNull(); } + @Test + public void shouldReturnResultWithUpdateActionAndId5SignatureWhenTargetingIsEmptyButId5SignatureIsPresent() { + // given + final String signature = "id5Signature"; + final ModuleContext moduleContext = + givenModuleContext(null, Future.failedFuture(new RuntimeException("error"))); + moduleContext.setId5Signature(signature); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + when(auctionResponsePayload.bidResponse()).thenReturn(givenBidResponse()); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + final BidResponse bidResponse = result + .payloadUpdate() + .apply(AuctionResponsePayloadImpl.of(givenBidResponse())) + .bidResponse(); + final JsonNode passthrough = bidResponse.getExt().getPrebid().getPassthrough(); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.update, InvocationResult::action); + assertThat(passthrough).isNotNull(); + assertThat(passthrough.get("optable").get("id5_signature").asText()).isEqualTo(signature); + } + @Test public void shouldReturnResultWithUpdateActionWhenAdvertiserTargetingOptionIsOn() { // given @@ -93,7 +126,8 @@ public void shouldReturnResultWithUpdateActionWhenAdvertiserTargetingOptionIsOn( "provider", List.of(new AudienceId("audienceId")), "keyspace", - 1)))); + 1)), + Future.succeededFuture(givenEmptyTargetingResult()))); when(auctionResponsePayload.bidResponse()).thenReturn(givenBidResponse()); // when @@ -127,14 +161,175 @@ public void shouldReturnResultWithUpdateActionWhenAdvertiserTargetingOptionIsOn( } @Test - public void shouldReturnResultWithNoActionWhenAdvertiserTargetingOptionIsOff() { + public void shouldEnrichBidResponseWithBothTargetingKeywordsAndId5Signature() { + // given + final String signature = "id5Signature"; + final ModuleContext moduleContext = givenModuleContext(List.of( + new Audience( + "provider", + List.of(new AudienceId("audienceId")), + "keyspace", + 1))); + moduleContext.setId5Signature(signature); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + when(auctionResponsePayload.bidResponse()).thenReturn(givenBidResponse()); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + final BidResponse bidResponse = result + .payloadUpdate() + .apply(AuctionResponsePayloadImpl.of(givenBidResponse())) + .bidResponse(); + final ObjectNode targeting = (ObjectNode) bidResponse.getSeatbid() + .getFirst() + .getBid() + .getFirst() + .getExt() + .get("prebid") + .get("targeting"); + final JsonNode passthrough = bidResponse.getExt().getPrebid().getPassthrough(); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.update, InvocationResult::action); + + assertThat(targeting.get("keyspace").asText()).isEqualTo("audienceId"); + assertThat(passthrough).isNotNull(); + assertThat(passthrough.get("optable").get("id5_signature").asText()).isEqualTo(signature); + } + + @Test + public void shouldEnrichBidResponseWithId5SignatureOnlyWhenNoTargeting() { + // given + final String signature = "id5Signature"; + final ModuleContext moduleContext = + givenModuleContext(null, Future.succeededFuture(givenEmptyTargetingResult())); + moduleContext.setId5Signature(signature); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + when(auctionResponsePayload.bidResponse()).thenReturn(givenBidResponse()); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + final BidResponse bidResponse = result + .payloadUpdate() + .apply(AuctionResponsePayloadImpl.of(givenBidResponse())) + .bidResponse(); + final JsonNode passthrough = bidResponse.getExt().getPrebid().getPassthrough(); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.update, InvocationResult::action); + assertThat(passthrough).isNotNull(); + assertThat(passthrough.get("optable").get("id5_signature").asText()).isEqualTo(signature); + } + + @Test + public void shouldReturnUpdateActionWhenTargetingIsPresentEvenIfOptableTargetingCallFails() { + // given + when(invocationContext.moduleContext()).thenReturn(givenModuleContext( + List.of(new Audience( + "provider", + List.of(new AudienceId("audienceId")), + "keyspace", + 1)), + Future.failedFuture(new RuntimeException("error")))); + when(auctionResponsePayload.bidResponse()).thenReturn(givenBidResponse()); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + final BidResponse bidResponse = result + .payloadUpdate() + .apply(AuctionResponsePayloadImpl.of(givenBidResponse())) + .bidResponse(); + final ObjectNode targeting = (ObjectNode) bidResponse.getSeatbid() + .getFirst() + .getBid() + .getFirst() + .getExt() + .get("prebid") + .get("targeting"); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.update, InvocationResult::action); + assertThat(targeting.get("keyspace").asText()).isEqualTo("audienceId"); + } + + @Test + public void shouldReturnNoActionWhenOptableTargetingCallFailsAndTargetingIsEmptyAndNoId5Signature() { + // given + when(invocationContext.moduleContext()).thenReturn( + givenModuleContext(null, Future.failedFuture(new RuntimeException("error")))); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.no_action, InvocationResult::action); + assertThat(result.payloadUpdate()).isNull(); + } + + @Test + public void shouldReturnUpdateActionWithId5SignatureWhenOptableTargetingCallFailsAndTargetingIsEmpty() { + // given + final String signature = "id5Signature"; + final ModuleContext moduleContext = + givenModuleContext(null, Future.failedFuture(new RuntimeException("error"))); + moduleContext.setId5Signature(signature); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + when(auctionResponsePayload.bidResponse()).thenReturn(givenBidResponse()); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + final BidResponse bidResponse = result + .payloadUpdate() + .apply(AuctionResponsePayloadImpl.of(givenBidResponse())) + .bidResponse(); + final JsonNode passthrough = bidResponse.getExt().getPrebid().getPassthrough(); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.update, InvocationResult::action); + assertThat(passthrough).isNotNull(); + assertThat(passthrough.get("optable").get("id5_signature").asText()).isEqualTo(signature); + } + + @Test + public void shouldReturnNoActionWhenTargetingCallFailsAndNoBidsAndNoId5Signature() { // given when(invocationContext.moduleContext()).thenReturn(givenModuleContext(List.of( new Audience( "provider", List.of(new AudienceId("audienceId")), "keyspace", - 1)))); + 1)), + Future.failedFuture(new RuntimeException("error")))); // when final Future> future = @@ -147,10 +342,116 @@ public void shouldReturnResultWithNoActionWhenAdvertiserTargetingOptionIsOff() { assertThat(result).isNotNull() .returns(InvocationStatus.success, InvocationResult::status) .returns(InvocationAction.no_action, InvocationResult::action); + assertThat(result.payloadUpdate()).isNull(); } @Test - public void shouldReturnSuccessWhenSkipEnrichmentIsTrue() { + public void shouldReturnUpdateActionWithId5SignatureWhenTargetingCallFailsAndNoBids() { + // given + final String signature = "id5Signature"; + final ModuleContext moduleContext = givenModuleContext(List.of( + new Audience( + "provider", + List.of(new AudienceId("audienceId")), + "keyspace", + 1)), + Future.failedFuture(new RuntimeException("error"))); + moduleContext.setId5Signature(signature); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + final BidResponse bidlessResponse = BidResponse.builder().build(); + when(auctionResponsePayload.bidResponse()).thenReturn(bidlessResponse); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + final BidResponse bidResponse = result + .payloadUpdate() + .apply(AuctionResponsePayloadImpl.of(bidlessResponse)) + .bidResponse(); + final JsonNode passthrough = bidResponse.getExt().getPrebid().getPassthrough(); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.update, InvocationResult::action); + assertThat(passthrough).isNotNull(); + assertThat(passthrough.get("optable").get("id5_signature").asText()).isEqualTo(signature); + } + + @Test + public void shouldReturnNoActionWhenAdserverTargetingIsDisabledAndNoId5Signature() { + // given + final OptableTargetingProperties properties = givenOptableTargetingProperties(false); + properties.setAdserverTargeting(false); + final ConfigResolver configResolver = new ConfigResolver(mapper, jsonMerger, properties); + target = new OptableTargetingAuctionResponseHook(configResolver, mapper, jsonMerger); + when(invocationContext.accountConfig()).thenReturn(mapper.valueToTree(properties)); + when(invocationContext.moduleContext()).thenReturn(givenModuleContext(List.of( + new Audience( + "provider", + List.of(new AudienceId("audienceId")), + "keyspace", + 1)), + Future.failedFuture(new RuntimeException("error")))); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.no_action, InvocationResult::action); + assertThat(result.payloadUpdate()).isNull(); + } + + @Test + public void shouldReturnUpdateActionWithId5SignatureWhenAdserverTargetingIsDisabled() { + // given + final String signature = "id5Signature"; + final OptableTargetingProperties properties = givenOptableTargetingProperties(false); + properties.setAdserverTargeting(false); + final ConfigResolver configResolver = new ConfigResolver(mapper, jsonMerger, properties); + target = new OptableTargetingAuctionResponseHook(configResolver, mapper, jsonMerger); + when(invocationContext.accountConfig()).thenReturn(mapper.valueToTree(properties)); + final ModuleContext moduleContext = givenModuleContext(List.of( + new Audience( + "provider", + List.of(new AudienceId("audienceId")), + "keyspace", + 1)), + Future.failedFuture(new RuntimeException("error"))); + moduleContext.setId5Signature(signature); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + final BidResponse bidResponse = result + .payloadUpdate() + .apply(AuctionResponsePayloadImpl.of(givenBidResponse())) + .bidResponse(); + final JsonNode passthrough = bidResponse.getExt().getPrebid().getPassthrough(); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.update, InvocationResult::action); + assertThat(passthrough).isNotNull(); + assertThat(passthrough.get("optable").get("id5_signature").asText()).isEqualTo(signature); + } + + @Test + public void shouldReturnNoActionWhenSkipEnrichmentIsTrueAndNoId5Signature() { // given final ModuleContext moduleContext = givenModuleContext(); moduleContext.setShouldSkipEnrichment(true); @@ -167,6 +468,36 @@ public void shouldReturnSuccessWhenSkipEnrichmentIsTrue() { assertThat(result).isNotNull() .returns(InvocationStatus.success, InvocationResult::status) .returns(InvocationAction.no_action, InvocationResult::action); + assertThat(result.payloadUpdate()).isNull(); + } + + @Test + public void shouldReturnUpdateActionWithId5SignatureWhenSkipEnrichmentIsTrue() { + // given + final String signature = "id5Signature"; + final ModuleContext moduleContext = givenModuleContext(); + moduleContext.setShouldSkipEnrichment(true); + moduleContext.setId5Signature(signature); + when(invocationContext.moduleContext()).thenReturn(moduleContext); + + // when + final Future> future = + target.call(auctionResponsePayload, invocationContext); + final InvocationResult result = future.result(); + final BidResponse bidResponse = result + .payloadUpdate() + .apply(AuctionResponsePayloadImpl.of(givenBidResponse())) + .bidResponse(); + final JsonNode passthrough = bidResponse.getExt().getPrebid().getPassthrough(); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat(result).isNotNull() + .returns(InvocationStatus.success, InvocationResult::status) + .returns(InvocationAction.update, InvocationResult::action); + assertThat(passthrough).isNotNull(); + assertThat(passthrough.get("optable").get("id5_signature").asText()).isEqualTo(signature); } private ObjectNode givenAccountConfig(boolean cacheEnabled) { diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHookTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHookTest.java index 894c8082175..c804be0b508 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHookTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHookTest.java @@ -80,7 +80,8 @@ void setUp() { when(userFpdActivityMask.maskDevice(any(), anyBoolean(), anyBoolean())) .thenAnswer(answer -> answer.getArgument(0)); configResolver = new ConfigResolver(mapper, jsonMerger, givenOptableTargetingProperties(false)); - targetingRequestExecutor = new TargetingRequestExecutor(optableTargeting, userFpdActivityMask, timeoutFactory); + targetingRequestExecutor = new TargetingRequestExecutor( + optableTargeting, userFpdActivityMask, timeoutFactory, 0.01); target = new OptableTargetingProcessedAuctionRequestHook( configResolver, targetingRequestExecutor, CompositeHookExecutionPlan.of(ExecutionPlan.empty()), 0.01); @@ -156,6 +157,50 @@ void callShouldReturnResultWithUpdateActionWhenOptableTargetingReturnsTargeting( .containsExactly("id"); } + @Test + void callShouldSetId5SignatureOnModuleContextWhenTargetingResultContainsId5Signature() { + // given + final String refValue = "refValue"; + final String signature = "id5Signature"; + final Eid id5Eid = givenId5Eid(refValue); + final ObjectNode refs = givenRefsObject(refValue, signature); + when(auctionRequestPayload.bidRequest()).thenReturn(givenBidRequest()); + when(optableTargeting.getTargeting(any(), any(), any(), any())) + .thenReturn(Future.succeededFuture(givenTargetingResult(List.of(id5Eid), null, refs))); + + // when + final Future> future = target.call(auctionRequestPayload, + invocationContext); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat((ModuleContext) future.result().moduleContext()) + .isNotNull() + .extracting(ModuleContext::getId5Signature) + .isEqualTo(signature); + } + + @Test + void callShouldLeaveId5SignatureNullWhenTargetingResultHasNoId5Signature() { + // given + when(auctionRequestPayload.bidRequest()).thenReturn(givenBidRequest()); + when(optableTargeting.getTargeting(any(), any(), any(), any())) + .thenReturn(Future.succeededFuture(givenTargetingResult())); + + // when + final Future> future = target.call(auctionRequestPayload, + invocationContext); + + // then + assertThat(future).isNotNull(); + assertThat(future.succeeded()).isTrue(); + assertThat((ModuleContext) future.result().moduleContext()) + .isNotNull() + .extracting(ModuleContext::getId5Signature) + .isNull(); + } + @Test void callShouldReturnResultWithUpdateActionWhenEarlyOptableCallIsEnabled() { // given diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/AuctionResponseValidatorTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/AuctionResponseValidatorTest.java index 51c5c33890f..a102e0b8a3a 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/AuctionResponseValidatorTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/AuctionResponseValidatorTest.java @@ -53,7 +53,7 @@ public void shouldReturnSuccessStatus() { // given final BidResponse bidResponse = BidResponse.builder() .seatbid(List.of(SeatBid.builder() - .bid(List.of(Bid.builder().build())) + .bid(List.of(Bid.builder().build())) .build())) .build(); diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestCleanerTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestCleanerTest.java index 6aa4ebff3a8..606c89ee102 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestCleanerTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestCleanerTest.java @@ -33,7 +33,8 @@ public void shouldKeepOtherUserExtOptableTags() { // given final User user = givenUser(); ((com.fasterxml.jackson.databind.node.ObjectNode) user.getExt().getProperty("optable")) - .put("other", "value"); + .put("other", "value") + .put("id5_signature", "signature"); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(givenBidRequest(bidRequest -> bidRequest.user(user))); @@ -50,6 +51,7 @@ public void shouldKeepOtherUserExtOptableTags() { .satisfies(optable -> { assertThat(optable.has("other")).isTrue(); assertThat(optable.has("email")).isFalse(); + assertThat(optable.has("id5_signature")).isFalse(); }); } } diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestEnricherTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestEnricherTest.java index 71ee889008f..eafc8c85dd9 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestEnricherTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidRequestEnricherTest.java @@ -1,6 +1,5 @@ package org.prebid.server.hooks.modules.optable.targeting.v1.core; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Data; import com.iab.openrtb.request.Eid; @@ -79,11 +78,11 @@ public void shouldReturnEnrichedBidRequestWhenTargetingResultsIsPresent() { public void shouldNotAddEidWhenSourceAlreadyPresent() { // given final TargetingResult targetingResult = givenTargetingResultWithEids(List.of( - givenEid("inserter", "source", List.of(givenUid("id2", 3, null)), null))); + givenEid("inserter", "source", List.of(givenUid("id2", 3))))); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("inserter", "source", List.of(givenUid("id", null, null)), null), - givenEid("inserter", "source1", List.of(givenUid("id", null, null)), null))); + givenEid("inserter", "source", List.of(givenUid("id", null))), + givenEid("inserter", "source1", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); // when @@ -101,11 +100,11 @@ public void shouldNotAddEidWhenSourceAlreadyPresent() { public void shouldAddEidWhenSourceIsNotAlreadyPresent() { // given final TargetingResult targetingResult = givenTargetingResultWithEids(List.of( - givenEid("inserter", "source3", List.of(givenUid("id2", 3, null)), null))); + givenEid("inserter", "source3", List.of(givenUid("id2", 3))))); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("inserter", "source1", List.of(givenUid("id", null, null)), null), - givenEid("inserter", "source2", List.of(givenUid("id", null, null)), null))); + givenEid("inserter", "source1", List.of(givenUid("id", null))), + givenEid("inserter", "source2", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); // when @@ -123,11 +122,11 @@ public void shouldAddEidWhenSourceIsNotAlreadyPresent() { public void shouldSkipEidWhenOptableSourceIsAlreadyPresent() { // given final TargetingResult targetingResult = givenTargetingResultWithEids(List.of( - givenEid("optable.co", "source2", List.of(givenUid("id2", 3, null)), null))); + givenEid("optable.co", "source2", List.of(givenUid("id2", 3))))); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("optable.co", "source1", List.of(givenUid("id", null, null)), null), - givenEid("optable.co", "source2", List.of(givenUid("id", null, null)), null))); + givenEid("optable.co", "source1", List.of(givenUid("id", null))), + givenEid("optable.co", "source2", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); // when @@ -151,11 +150,11 @@ public void shouldSkipEidWhenOptableSourceIsAlreadyPresent() { public void shouldMergeEidWhenOptableSourceIsAlreadyPresent() { // given final TargetingResult targetingResult = givenTargetingResultWithEids(List.of( - givenEid("optable.co", "source2", List.of(givenUid("id2", 3, null)), null))); + givenEid("optable.co", "source2", List.of(givenUid("id2", 3))))); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("optable.co", "source1", List.of(givenUid("id", null, null)), null), - givenEid("optable.co", "source2", List.of(givenUid("id", null, null)), null))); + givenEid("optable.co", "source1", List.of(givenUid("id", null))), + givenEid("optable.co", "source2", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); final OptableTargetingProperties properties = new OptableTargetingProperties(); properties.setOptableInserterEidsMerge(Set.of("source2")); @@ -181,11 +180,11 @@ public void shouldMergeEidWhenOptableSourceIsAlreadyPresent() { public void shouldRemoveEidWhenOptableSourceIsAlreadyPresent() { // given final TargetingResult targetingResult = givenTargetingResultWithEids(List.of( - givenEid("optable.co", "source2", List.of(givenUid("id2", 3, null)), null))); + givenEid("optable.co", "source2", List.of(givenUid("id2", 3))))); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("optable.co", "source1", List.of(givenUid("id", null, null)), null), - givenEid("optable.co", "source2", List.of(givenUid("id", null, null)), null))); + givenEid("optable.co", "source1", List.of(givenUid("id", null))), + givenEid("optable.co", "source2", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); final OptableTargetingProperties properties = new OptableTargetingProperties(); properties.setOptableInserterEidsIgnore(Set.of("source2")); @@ -207,8 +206,8 @@ public void shouldRemoveEidWhenOptableSourceIsAlreadyPresentAndEmptyTargeting() final TargetingResult targetingResult = givenTargetingResultWithEids(List.of()); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("optable.co", "source1", List.of(givenUid("id", null, null)), null), - givenEid("optable.co", "source2", List.of(givenUid("id", null, null)), null))); + givenEid("optable.co", "source1", List.of(givenUid("id", null))), + givenEid("optable.co", "source2", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); final OptableTargetingProperties properties = new OptableTargetingProperties(); properties.setOptableInserterEidsIgnore(Set.of("source2")); @@ -228,11 +227,11 @@ public void shouldRemoveEidWhenOptableSourceIsAlreadyPresentAndEmptyTargeting() public void shouldReplaceEidWhenOptableSourceIsAlreadyPresent() { // given final TargetingResult targetingResult = givenTargetingResultWithEids(List.of( - givenEid("optable.co", "source2", List.of(givenUid("id2", 3, null)), null))); + givenEid("optable.co", "source2", List.of(givenUid("id2", 3))))); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("optable.co", "source1", List.of(givenUid("id", null, null)), null), - givenEid("optable.co", "source2", List.of(givenUid("id", null, null)), null))); + givenEid("optable.co", "source1", List.of(givenUid("id", null))), + givenEid("optable.co", "source2", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); final OptableTargetingProperties properties = new OptableTargetingProperties(); properties.setOptableInserterEidsReplace(Set.of("source2")); @@ -258,11 +257,11 @@ public void shouldReplaceEidWhenOptableSourceIsAlreadyPresent() { public void shouldReplaceEidWhenOptableSourceIsPresentInBothMergeAndReplaceLists() { // given final TargetingResult targetingResult = givenTargetingResultWithEids(List.of( - givenEid("optable.co", "source2", List.of(givenUid("id2", 3, null)), null))); + givenEid("optable.co", "source2", List.of(givenUid("id2", 3))))); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("optable.co", "source1", List.of(givenUid("id", null, null)), null), - givenEid("optable.co", "source2", List.of(givenUid("id", null, null)), null))); + givenEid("optable.co", "source1", List.of(givenUid("id", null))), + givenEid("optable.co", "source2", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); final OptableTargetingProperties properties = new OptableTargetingProperties(); properties.setOptableInserterEidsReplace(Set.of("source2")); @@ -289,11 +288,11 @@ public void shouldReplaceEidWhenOptableSourceIsPresentInBothMergeAndReplaceLists public void shouldNotMergeOriginEidsWithTheSameSource() { // given final TargetingResult targetingResult = givenTargetingResultWithEids(List.of( - givenEid("inserter", "source3", List.of(givenUid("id2", 3, null)), null))); + givenEid("inserter", "source3", List.of(givenUid("id2", 3))))); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("inserter", "source", List.of(givenUid("id", null, null)), null), - givenEid("inserter", "source", List.of(givenUid("id", null, null)), null))); + givenEid("inserter", "source", List.of(givenUid("id", null))), + givenEid("inserter", "source", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); // when @@ -311,7 +310,7 @@ public void shouldNotMergeOriginEidsWithTheSameSource() { public void shouldApplyOriginEidsWhenTargetingIsEmpty() { // given final TargetingResult targetingResult = givenTargetingResultWithEids(List.of( - givenEid("inserter", "source3", List.of(givenUid("id2", 3, null)), null))); + givenEid("inserter", "source3", List.of(givenUid("id2", 3))))); final BidRequest bidRequest = givenBidRequestWithUserEids(Collections.emptyList()); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); @@ -333,8 +332,8 @@ public void shouldApplyTargetingEidsWhenOriginListIsEmpty() { final TargetingResult targetingResult = givenTargetingResultWithEids(Collections.emptyList()); final BidRequest bidRequest = givenBidRequestWithUserEids(List.of( - givenEid("inserter", "source", List.of(givenUid("id", null, null)), null), - givenEid("inserter", "source1", List.of(givenUid("id", null, null)), null))); + givenEid("inserter", "source", List.of(givenUid("id", null))), + givenEid("inserter", "source1", List.of(givenUid("id", null))))); final AuctionRequestPayload auctionRequestPayload = AuctionRequestPayloadImpl.of(bidRequest); // when @@ -514,20 +513,18 @@ public void shouldReturnOriginBidRequestWhenTargetingResultsIsEmpty() { assertThat(user.getData()).isNull(); } - private Eid givenEid(String inserter, String source, List uids, ObjectNode ext) { + private Eid givenEid(String inserter, String source, List uids) { return Eid.builder() .inserter(inserter) .source(source) .uids(uids) - .ext(ext) .build(); } - private Uid givenUid(String id, Integer atype, ObjectNode ext) { + private Uid givenUid(String id, Integer atype) { return Uid.builder() .id(id) .atype(atype) - .ext(ext) .build(); } diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/CacheTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/CacheTest.java index 1917fd6ca27..e0a723bbfa3 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/CacheTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/CacheTest.java @@ -109,6 +109,7 @@ private TargetingResult givenTargetingResult() { List.of(new AudienceId("1")), "keyspace", 0)), - new Ortb2(new User(null, null))); + new Ortb2(new User(null, null)), + null); } } diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/ExtUserOptableResolverTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/ExtUserOptableResolverTest.java new file mode 100644 index 00000000000..b3142c173f2 --- /dev/null +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/ExtUserOptableResolverTest.java @@ -0,0 +1,64 @@ +package org.prebid.server.hooks.modules.optable.targeting.v1.core; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import org.junit.jupiter.api.Test; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.ExtUserOptable; +import org.prebid.server.json.ObjectMapperProvider; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ExtUserOptableResolverTest { + + @Test + public void shouldResolveExtUserOptableWhenNodeIsValid() { + // given + final ObjectNode node = ObjectMapperProvider.mapper().createObjectNode(); + node.set("email", TextNode.valueOf("user@example.com")); + node.set("phone", TextNode.valueOf("123")); + node.set("zip", TextNode.valueOf("321")); + node.set("vid", TextNode.valueOf("vid")); + node.set("id5_signature", TextNode.valueOf("signature")); + + // when + final ExtUserOptable result = ExtUserOptableResolver.resolveExtUserOptable(node, 1.0); + + // then + assertThat(result).isNotNull() + .returns("user@example.com", ExtUserOptable::getEmail) + .returns("123", ExtUserOptable::getPhone) + .returns("321", ExtUserOptable::getZip) + .returns("vid", ExtUserOptable::getVid) + .returns("signature", ExtUserOptable::getId5Signature); + } + + @Test + public void shouldReturnNullWhenNodeIsNotParseable() { + // given + final ObjectNode node = ObjectMapperProvider.mapper().createObjectNode(); + node.set("email", ObjectMapperProvider.mapper().createArrayNode().add(1).add(2)); + + // when + final ExtUserOptable result = ExtUserOptableResolver.resolveExtUserOptable(node, 1.0); + + // then + assertThat(result).isNull(); + } + + @Test + public void shouldResolveExtUserOptableWhenNodeIsEmpty() { + // given + final ObjectNode node = ObjectMapperProvider.mapper().createObjectNode(); + + // when + final ExtUserOptable result = ExtUserOptableResolver.resolveExtUserOptable(node, 1.0); + + // then + assertThat(result).isNotNull() + .returns(null, ExtUserOptable::getEmail) + .returns(null, ExtUserOptable::getPhone) + .returns(null, ExtUserOptable::getZip) + .returns(null, ExtUserOptable::getVid) + .returns(null, ExtUserOptable::getId5Signature); + } +} diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5ResolverTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5ResolverTest.java new file mode 100644 index 00000000000..da0e5bb4161 --- /dev/null +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5ResolverTest.java @@ -0,0 +1,339 @@ +package org.prebid.server.hooks.modules.optable.targeting.v1.core; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import com.iab.openrtb.request.Eid; +import com.iab.openrtb.request.Uid; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.Ortb2; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.TargetingResult; +import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.User; +import org.prebid.server.json.ObjectMapperProvider; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class Id5ResolverTest { + + private ObjectMapper mapper; + + @BeforeEach + public void setUp() { + mapper = ObjectMapperProvider.mapper(); + } + + @Test + public void shouldReturnNullWhenSignatureIsJsonNull() { + // given + final ObjectNode uidExt = mapper.createObjectNode(); + uidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("refValue"))); + final Eid eid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id").ext(uidExt).build())) + .build(); + final ObjectNode refs = mapper.createObjectNode(); + refs.set("refValue", mapper.createObjectNode().putNull("signature")); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(eid), null)), + refs); + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + // then + assertThat(result).isNull(); + } + + @Test + public void shouldReturnNullWhenTargetingResultIsNull() { + // when + final String result = Id5Resolver.resolveId5Signature(null); + + // then + assertThat(result).isNull(); + } + + @Test + public void shouldReturnNullWhenOrtb2IsNull() { + // given + final TargetingResult targetingResult = new TargetingResult(List.of(), null, null); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isNull(); + } + + @Test + public void shouldReturnNullWhenUserHasNoEids() { + // given + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(null, null)), + null); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isNull(); + } + + @Test + public void shouldReturnNullWhenEidsDoNotMatchOptableAndId5Source() { + // given + final Eid eid = Eid.builder() + .source("other-source") + .inserter("other-inserter") + .uids(List.of(Uid.builder().id("id").build())) + .build(); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(eid), null)), + null); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isNull(); + } + + @Test + public void shouldReturnNullWhenMatchingEidButRefsAreAbsent() { + // given + final ObjectNode uidExt = mapper.createObjectNode(); + uidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("refValue"))); + + final Eid eid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id").ext(uidExt).build())) + .build(); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(eid), null)), + null); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isNull(); + } + + @Test + public void shouldReturnNullWhenRefsDoNotContainResolvedRef() { + // given + final ObjectNode uidExt = mapper.createObjectNode(); + uidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("refValue"))); + + final Eid eid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id").ext(uidExt).build())) + .build(); + final ObjectNode refs = mapper.createObjectNode(); + refs.set("otherRef", mapper.createObjectNode() + .set("signature", TextNode.valueOf("signatureValue"))); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(eid), null)), + refs); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isNull(); + } + + @Test + public void shouldReturnSignatureWhenAllConditionsAreMet() { + // given + final ObjectNode uidExt = mapper.createObjectNode(); + uidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("refValue"))); + + final Eid eid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id").ext(uidExt).build())) + .build(); + final ObjectNode refs = mapper.createObjectNode(); + refs.set("refValue", mapper.createObjectNode() + .set("signature", TextNode.valueOf("signatureValue"))); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(eid), null)), + refs); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isEqualTo("signatureValue"); + } + + @Test + public void shouldReturnSignatureWhenMultipleMatchingEidsExist() { + // given + final ObjectNode firstUidExt = mapper.createObjectNode(); + firstUidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("firstRef"))); + + final ObjectNode secondUidExt = mapper.createObjectNode(); + secondUidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("secondRef"))); + + final Eid firstEid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id1").ext(firstUidExt).build())) + .build(); + final Eid secondEid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id2").ext(secondUidExt).build())) + .build(); + final ObjectNode refs = mapper.createObjectNode(); + refs.set("firstRef", mapper.createObjectNode() + .set("signature", TextNode.valueOf("firstSignature"))); + refs.set("secondRef", mapper.createObjectNode() + .set("signature", TextNode.valueOf("secondSignature"))); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(firstEid, secondEid), null)), + refs); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isEqualTo("firstSignature"); + } + + @Test + public void shouldReturnSignatureFromSecondMatchingEidWhenFirstRefNotInRefs() { + // given + final ObjectNode firstUidExt = mapper.createObjectNode(); + firstUidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("firstRef"))); + + final ObjectNode secondUidExt = mapper.createObjectNode(); + secondUidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("secondRef"))); + + final Eid firstEid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id1").ext(firstUidExt).build())) + .build(); + final Eid secondEid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id2").ext(secondUidExt).build())) + .build(); + final ObjectNode refs = mapper.createObjectNode(); + refs.set("secondRef", mapper.createObjectNode() + .set("signature", TextNode.valueOf("secondSignature"))); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(firstEid, secondEid), null)), + refs); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isEqualTo("secondSignature"); + } + + @Test + public void shouldReturnNullWhenRefEntrySignatureIsBlank() { + // given + final ObjectNode uidExt = mapper.createObjectNode(); + uidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("refValue"))); + + final Eid eid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id").ext(uidExt).build())) + .build(); + final ObjectNode refs = mapper.createObjectNode(); + refs.set("refValue", mapper.createObjectNode() + .set("signature", TextNode.valueOf(" "))); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(eid), null)), + refs); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isNull(); + } + + @Test + public void shouldReturnNullWhenRefEntrySignatureIsContainerNode() { + // given + final ObjectNode uidExt = mapper.createObjectNode(); + uidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("refValue"))); + + final Eid eid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id").ext(uidExt).build())) + .build(); + final ObjectNode refs = mapper.createObjectNode(); + refs.set("refValue", mapper.createObjectNode() + .set("signature", mapper.createObjectNode())); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(eid), null)), + refs); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isNull(); + } + + @Test + public void shouldReturnNullWhenRefEntryHasNoSignature() { + // given + final ObjectNode uidExt = mapper.createObjectNode(); + uidExt.set("optable", mapper.createObjectNode() + .set("ref", TextNode.valueOf("refValue"))); + + final Eid eid = Eid.builder() + .source("id5-sync.com") + .inserter("optable.co") + .uids(List.of(Uid.builder().id("id").ext(uidExt).build())) + .build(); + final ObjectNode refs = mapper.createObjectNode(); + refs.set("refValue", mapper.createObjectNode() + .set("other", TextNode.valueOf("value"))); + final TargetingResult targetingResult = new TargetingResult( + List.of(), + new Ortb2(new User(List.of(eid), null)), + refs); + + // when + final String result = Id5Resolver.resolveId5Signature(targetingResult); + + // then + assertThat(result).isNull(); + } +} diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5SignatureBidResponseEnricherTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5SignatureBidResponseEnricherTest.java new file mode 100644 index 00000000000..d9eb8bd1798 --- /dev/null +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/Id5SignatureBidResponseEnricherTest.java @@ -0,0 +1,122 @@ +package org.prebid.server.hooks.modules.optable.targeting.v1.core; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import com.iab.openrtb.response.BidResponse; +import org.junit.jupiter.api.Test; +import org.prebid.server.hooks.execution.v1.auction.AuctionResponsePayloadImpl; +import org.prebid.server.hooks.v1.auction.AuctionResponsePayload; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.json.JsonMerger; +import org.prebid.server.json.ObjectMapperProvider; +import org.prebid.server.proto.openrtb.ext.response.ExtBidResponse; +import org.prebid.server.proto.openrtb.ext.response.ExtBidResponsePrebid; + +import static org.assertj.core.api.Assertions.assertThat; + +public class Id5SignatureBidResponseEnricherTest { + + private final JacksonMapper jacksonMapper = new JacksonMapper(ObjectMapperProvider.mapper()); + private final JsonMerger jsonMerger = new JsonMerger(jacksonMapper); + + @Test + public void shouldReturnOriginBidResponseWhenId5SignatureIsNull() { + // given + final BidResponse bidResponse = BidResponse.builder().build(); + final AuctionResponsePayload payload = AuctionResponsePayloadImpl.of(bidResponse); + final Id5SignatureBidResponseEnricher enricher = + Id5SignatureBidResponseEnricher.of(null, ObjectMapperProvider.mapper(), jsonMerger); + + // when + final AuctionResponsePayload result = enricher.apply(payload); + + // then + assertThat(result.bidResponse()).isSameAs(bidResponse); + } + + @Test + public void shouldReturnOriginBidResponseWhenId5SignatureIsEmpty() { + // given + final BidResponse bidResponse = BidResponse.builder().build(); + final AuctionResponsePayload payload = AuctionResponsePayloadImpl.of(bidResponse); + final Id5SignatureBidResponseEnricher enricher = + Id5SignatureBidResponseEnricher.of("", ObjectMapperProvider.mapper(), jsonMerger); + + // when + final AuctionResponsePayload result = enricher.apply(payload); + + // then + assertThat(result.bidResponse()).isSameAs(bidResponse); + } + + @Test + public void shouldAddId5SignatureToPassthroughWhenExtIsAbsent() { + // given + final BidResponse bidResponse = BidResponse.builder().build(); + final AuctionResponsePayload payload = AuctionResponsePayloadImpl.of(bidResponse); + final Id5SignatureBidResponseEnricher enricher = + Id5SignatureBidResponseEnricher.of("signature", ObjectMapperProvider.mapper(), jsonMerger); + + // when + final AuctionResponsePayload result = enricher.apply(payload); + + // then + final BidResponse enriched = result.bidResponse(); + assertThat(enriched.getExt()).isNotNull(); + assertThat(enriched.getExt().getPrebid()).isNotNull(); + final JsonNode passthrough = enriched.getExt().getPrebid().getPassthrough(); + assertThat(passthrough).isNotNull(); + assertThat(passthrough.get("optable").get("id5_signature").asText()).isEqualTo("signature"); + } + + @Test + public void shouldMergeId5SignatureWithExistingPassthrough() { + // given + final ObjectNode existingPassthrough = ObjectMapperProvider.mapper().createObjectNode(); + existingPassthrough.set("other", ObjectMapperProvider.mapper().createObjectNode() + .set("value", TextNode.valueOf("otherValue"))); + existingPassthrough.set("optable", ObjectMapperProvider.mapper().createObjectNode() + .set("existing", TextNode.valueOf("preserved"))); + + final ExtBidResponse ext = ExtBidResponse.builder() + .prebid(ExtBidResponsePrebid.builder() + .passthrough(existingPassthrough) + .build()) + .build(); + final BidResponse bidResponse = BidResponse.builder().ext(ext).build(); + final AuctionResponsePayload payload = AuctionResponsePayloadImpl.of(bidResponse); + final Id5SignatureBidResponseEnricher enricher = + Id5SignatureBidResponseEnricher.of("signature", ObjectMapperProvider.mapper(), jsonMerger); + + // when + final AuctionResponsePayload result = enricher.apply(payload); + + // then + final JsonNode passthrough = result.bidResponse().getExt().getPrebid().getPassthrough(); + assertThat(passthrough.get("optable").get("id5_signature").asText()).isEqualTo("signature"); + assertThat(passthrough.get("optable").get("existing").asText()).isEqualTo("preserved"); + assertThat(passthrough.get("other").get("value").asText()).isEqualTo("otherValue"); + } + + @Test + public void shouldPreserveExistingPrebidFieldsWhenAddingPassthrough() { + // given + final ExtBidResponse ext = ExtBidResponse.builder() + .prebid(ExtBidResponsePrebid.builder().build()) + .build(); + final BidResponse bidResponse = BidResponse.builder().ext(ext).build(); + final AuctionResponsePayload payload = AuctionResponsePayloadImpl.of(bidResponse); + final Id5SignatureBidResponseEnricher enricher = + Id5SignatureBidResponseEnricher.of("signature", ObjectMapperProvider.mapper(), jsonMerger); + + // when + final AuctionResponsePayload result = enricher.apply(payload); + + // then + final ExtBidResponsePrebid prebid = result.bidResponse().getExt().getPrebid(); + assertThat(prebid).isNotNull(); + assertThat(prebid.getPassthrough().get("optable").get("id5_signature").asText()) + .isEqualTo("signature"); + } +} diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/IdsMapperTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/IdsMapperTest.java index 39693661629..ee273761f04 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/IdsMapperTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/IdsMapperTest.java @@ -32,7 +32,7 @@ public class IdsMapperTest { @BeforeEach public void setUp() { - target = new IdsMapper(objectMapper, 0.01); + target = new IdsMapper(0.01); } @Test @@ -56,7 +56,8 @@ public void shouldMapBidRequestToAllPossibleIds() { .doesNotContain(Id.of(Id.APPLE_IDFA, "ifa")) .contains(Id.of(Id.ID5, "id5_id")) .contains(Id.of(Id.UTIQ, "utiq_id")) - .contains(Id.of("c", "test_id")); + .contains(Id.of("c", "test_id")) + .contains(Id.of(Id.DEVICE_IP_V_6, "0:0:0:0:0:0:0:1")); } @Test @@ -71,6 +72,17 @@ public void shouldMapNothing() { assertThat(ids).isNotNull(); } + @Test + public void shouldMapIpv6WhenPresent() { + final BidRequest bidRequest = givenBidRequestWithEids(Map.of()); + + final List ids = target.toIds(bidRequest, Map.of()); + + assertThat(ids).isNotNull() + .contains(Id.of(Id.EMAIL, "email")) + .contains(Id.of(Id.DEVICE_IP_V_6, "0:0:0:0:0:0:0:1")); + } + private BidRequest givenBidRequestWithEids(Map eids) { final JsonNode extUserOptable = objectMapper.convertValue(givenOptable(), JsonNode.class); final ExtUser extUser = ExtUser.builder().build(); diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolverTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolverTest.java index 9621758cab0..51adfda9952 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolverTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolverTest.java @@ -1,9 +1,12 @@ package org.prebid.server.hooks.modules.optable.targeting.v1.core; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; import com.iab.gpp.encoder.GppModel; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Regs; import com.iab.openrtb.request.User; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -11,6 +14,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.auction.gpp.model.GppContext; import org.prebid.server.auction.model.AuctionContext; +import org.prebid.server.hooks.modules.optable.targeting.model.App; import org.prebid.server.hooks.modules.optable.targeting.model.OptableAttributes; import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties; import org.prebid.server.hooks.modules.optable.targeting.v1.BaseOptableTest; @@ -56,7 +60,7 @@ public void shouldResolveGdprAttributesForORTB26WhenConsentIsValid() { // when final OptableAttributes result = OptableAttributesResolver.resolveAttributes( - auctionContext, properties.getTimeout()); + auctionContext, properties.getTimeout(), 0.01); // then assertThat(result).isNotNull() @@ -75,7 +79,7 @@ public void shouldResolveGdprAttributesForORTB25WhenConsentIsValid() { // when final OptableAttributes result = OptableAttributesResolver.resolveAttributes( - auctionContext, properties.getTimeout()); + auctionContext, properties.getTimeout(), 0.01); // then assertThat(result).isNotNull() @@ -83,34 +87,6 @@ public void shouldResolveGdprAttributesForORTB25WhenConsentIsValid() { .returns("consent", OptableAttributes::getGdprConsent); } - private BidRequest givenBidRequestWithGdprORTB26(boolean isGdprEnabled, String consent) { - final User user = User.builder() - .consent(consent) - .build(); - - return BidRequest.builder() - .user(user) - .regs(Regs.builder() - .gdpr(isGdprEnabled ? 1 : 0) - .build()) - .build(); - } - - private BidRequest givenBidRequestWithGdprORTB25(boolean isGdprEnabled, String consent) { - final User user = User.builder() - .ext(ExtUser.builder() - .consent(consent) - .build()) - .build(); - - return BidRequest.builder() - .user(user) - .regs(Regs.builder() - .ext(ExtRegs.of(isGdprEnabled ? 1 : 0, null, null, null)) - .build()) - .build(); - } - @Test public void shouldNotResolveTcfAttributesWhenConsentIsNotValid() { // given @@ -124,7 +100,7 @@ public void shouldNotResolveTcfAttributesWhenConsentIsNotValid() { // when final OptableAttributes result = OptableAttributesResolver.resolveAttributes( - auctionContext, properties.getTimeout()); + auctionContext, properties.getTimeout(), 0.01); // then assertThat(result).isNotNull() @@ -145,7 +121,7 @@ public void shouldResolveGppAttributes() { // when final OptableAttributes result = OptableAttributesResolver.resolveAttributes( - auctionContext, properties.getTimeout()); + auctionContext, properties.getTimeout(), 0.01); // then assertThat(result).isNotNull() @@ -154,6 +130,113 @@ public void shouldResolveGppAttributes() { .returns(Set.of(1), OptableAttributes::getGppSid); } + @Test + public void shouldResolveAppWhenAppIsPresent() { + // given + final com.iab.openrtb.request.App ortbApp = com.iab.openrtb.request.App.builder() + .bundle("com.example.app") + .ver("1.2.3") + .build(); + final BidRequest bidRequest = BidRequest.builder() + .app(ortbApp) + .build(); + final AuctionContext auctionContext = givenAuctionContext(bidRequest, tcfContext, gppContext); + + // when + final OptableAttributes result = OptableAttributesResolver.resolveAttributes( + auctionContext, properties.getTimeout(), 0.01); + + // then + assertThat(result).isNotNull() + .returns(App.of("com.example.app", "1.2.3"), OptableAttributes::getApp); + } + + @Test + public void shouldNotResolveAppWhenAppIsAbsent() { + // given + final BidRequest bidRequest = BidRequest.builder().build(); + final AuctionContext auctionContext = givenAuctionContext(bidRequest, tcfContext, gppContext); + + // when + final OptableAttributes result = OptableAttributesResolver.resolveAttributes( + auctionContext, properties.getTimeout(), 0.01); + + // then + assertThat(result).isNotNull() + .returns(null, OptableAttributes::getApp); + } + + @Test + public void shouldResolveId5SignatureWhenPresentInUserExtOptable() { + // given + final BidRequest bidRequest = givenBidRequestWithId5Signature("signature"); + final AuctionContext auctionContext = givenAuctionContext(bidRequest, tcfContext, gppContext); + + // when + final OptableAttributes result = OptableAttributesResolver.resolveAttributes( + auctionContext, properties.getTimeout(), 0.01); + + // then + assertThat(result).isNotNull() + .returns("signature", OptableAttributes::getId5Signature); + } + + @Test + public void shouldNotResolveId5SignatureWhenAbsentInUserExtOptable() { + // given + final BidRequest bidRequest = givenBidRequestWithId5Signature(null); + final AuctionContext auctionContext = givenAuctionContext(bidRequest, tcfContext, gppContext); + + // when + final OptableAttributes result = OptableAttributesResolver.resolveAttributes( + auctionContext, properties.getTimeout(), 0.01); + + // then + assertThat(result).isNotNull() + .returns(null, OptableAttributes::getId5Signature); + } + + private BidRequest givenBidRequestWithId5Signature(String signature) { + final ObjectNode optable = mapper.createObjectNode(); + if (StringUtils.isNotEmpty(signature)) { + optable.set("id5_signature", TextNode.valueOf(signature)); + } + + final ExtUser extUser = ExtUser.builder().build(); + extUser.addProperty("optable", optable); + final User user = User.builder().ext(extUser).build(); + + return BidRequest.builder().user(user).build(); + } + + private BidRequest givenBidRequestWithGdprORTB26(boolean isGdprEnabled, String consent) { + final User user = User.builder() + .consent(consent) + .build(); + + return BidRequest.builder() + .user(user) + .regs(Regs.builder() + .gdpr(isGdprEnabled ? 1 : 0) + .build()) + .build(); + } + + private BidRequest givenBidRequestWithGdprORTB25(boolean isGdprEnabled, String consent) { + final User user = User.builder() + .ext(ExtUser.builder() + .consent(consent) + .build()) + .build(); + + return BidRequest.builder() + .user(user) + .regs(Regs.builder() + .ext(ExtRegs.of(isGdprEnabled ? 1 : 0, null, null, null)) + .build()) + .build(); + } + public AuctionContext givenAuctionContext(BidRequest bidRequest, TcfContext tcfContext, GppContext gppContext) { return AuctionContext.builder() .bidRequest(bidRequest) diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/QueryBuilderTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/QueryBuilderTest.java index 16d5953ef71..f8eb3a99c36 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/QueryBuilderTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/QueryBuilderTest.java @@ -1,9 +1,11 @@ package org.prebid.server.hooks.modules.optable.targeting.v1.core; import org.junit.jupiter.api.Test; +import org.prebid.server.hooks.modules.optable.targeting.model.App; import org.prebid.server.hooks.modules.optable.targeting.model.Id; import org.prebid.server.hooks.modules.optable.targeting.model.OptableAttributes; import org.prebid.server.hooks.modules.optable.targeting.model.Query; +import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties; import java.util.List; import java.util.Set; @@ -16,16 +18,21 @@ public class QueryBuilderTest { private final String idPrefixOrder = "c,c1"; + private OptableTargetingProperties properties() { + return givenProperties(idPrefixOrder, null); + } + @Test public void shouldSeparateAttributesFromIds() { // given final List ids = List.of(Id.of(Id.EMAIL, "email"), Id.of(Id.PHONE, "123")); // when - final Query query = QueryBuilder.build(ids, optableAttributes, idPrefixOrder); + final Query query = QueryBuilder.build(ids, optableAttributes, properties()); // then assertThat(query.getIds()).isEqualTo("&id=e%3Aemail&id=p%3A123"); + assertThat(query.getHid()).isEqualTo(""); assertThat(query.getAttributes()).isEqualTo("&gdpr_consent=tcf&gdpr=1&timeout=100ms&osdk=prebid-server"); } @@ -35,10 +42,11 @@ public void shouldBuildFullQueryString() { final List ids = List.of(Id.of(Id.EMAIL, "email"), Id.of(Id.PHONE, "123")); // when - final Query query = QueryBuilder.build(ids, optableAttributes, idPrefixOrder); + final Query query = QueryBuilder.build(ids, optableAttributes, properties()); // then assertThat(query.getIds()).isEqualTo("&id=e%3Aemail&id=p%3A123"); + assertThat(query.getHid()).isEqualTo(""); assertThat(query.getAttributes()).isEqualTo("&gdpr_consent=tcf&gdpr=1&timeout=100ms&osdk=prebid-server"); assertThat(query.toQueryString()) .isEqualTo("&id=e%3Aemail&id=p%3A123&gdpr_consent=tcf&gdpr=1&timeout=100ms&osdk=prebid-server"); @@ -50,7 +58,7 @@ public void shouldBuildQueryStringWhenHaveIds() { final List ids = List.of(Id.of(Id.EMAIL, "email"), Id.of(Id.PHONE, "123")); // when - final String query = QueryBuilder.build(ids, optableAttributes, idPrefixOrder).toQueryString(); + final String query = QueryBuilder.build(ids, optableAttributes, properties()).toQueryString(); // then assertThat(query).contains("e%3Aemail", "p%3A123"); @@ -62,7 +70,7 @@ public void shouldBuildQueryStringWithExtraAttributes() { final List ids = List.of(Id.of(Id.EMAIL, "email"), Id.of(Id.PHONE, "123")); // when - final String query = QueryBuilder.build(ids, optableAttributes, idPrefixOrder).toQueryString(); + final String query = QueryBuilder.build(ids, optableAttributes, properties()).toQueryString(); // then assertThat(query).contains("&gdpr=1", "&gdpr_consent=tcf", "&timeout=100ms"); @@ -78,7 +86,7 @@ public void shouldBuildQueryStringWithRightOrder() { Id.of("c", "234")); // when - final String query = QueryBuilder.build(ids, optableAttributes, idPrefixOrder).toQueryString(); + final String query = QueryBuilder.build(ids, optableAttributes, properties()).toQueryString(); // then assertThat(query).startsWith("&id=c%3A234&id=c1%3A123&id=id5%3AID5&id=e%3Aemail"); @@ -93,7 +101,7 @@ public void shouldBuildQueryStringWhenIdsListIsEmptyAndIpIsPresent() { .build(); // when - final Query query = QueryBuilder.build(ids, attributes, idPrefixOrder); + final Query query = QueryBuilder.build(ids, attributes, properties()); // then assertThat(query).isNotNull(); @@ -107,7 +115,7 @@ public void shouldNotBuildQueryStringWhenIdsListIsEmptyAndIpIsAbsent() { final OptableAttributes attributes = OptableAttributes.builder().build(); // when - final Query query = QueryBuilder.build(ids, attributes, idPrefixOrder); + final Query query = QueryBuilder.build(ids, attributes, properties()); // then assertThat(query).isNull(); @@ -124,7 +132,7 @@ public void shouldBuildQueryStringWithGppSid() { .build(); // when - final String query = QueryBuilder.build(ids, attributes, null).toQueryString(); + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); // then assertThat(query).contains("&gpp=DBABzw~1YNY~BVQqAAAAAgA"); @@ -144,7 +152,7 @@ public void shouldBuildQueryStringWithSingleGppSid() { .build(); // when - final String query = QueryBuilder.build(ids, attributes, null).toQueryString(); + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); // then assertThat(query).contains("&gpp_sid=7"); @@ -162,7 +170,7 @@ public void shouldLimitGppSidToTwoValues() { .build(); // when - final String query = QueryBuilder.build(ids, attributes, null).toQueryString(); + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); // then final String gppSidValue = query.split("gpp_sid=")[1].split("&")[0]; @@ -181,12 +189,331 @@ public void shouldNotIncludeGppSidWhenEmpty() { .build(); // when - final String query = QueryBuilder.build(ids, attributes, null).toQueryString(); + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); // then assertThat(query).doesNotContain("gpp_sid"); } + @Test + public void shouldBuildHidWhenHidPrefixesMatchIds() { + // given + final OptableTargetingProperties props = givenProperties(null, "c,i6"); + final List ids = List.of( + Id.of("c", "234"), + Id.of(Id.DEVICE_IP_V_6, "0:0:0:0:0:0:0:1")); + + // when + final Query query = QueryBuilder.build(ids, optableAttributes, props); + + // then + assertThat(query.getHid()).isEqualTo("&hid=c:234&hid=i6:0%3A0%3A0%3A0%3A0%3A0%3A0%3A1"); + } + + @Test + public void shouldExcludeDeviceIpV6FromIdsString() { + // given + final OptableTargetingProperties props = givenProperties(null, "i6"); + final List ids = List.of( + Id.of(Id.EMAIL, "email"), + Id.of(Id.DEVICE_IP_V_6, "0:0:0:0:0:0:0:1")); + + // when + final Query query = QueryBuilder.build(ids, optableAttributes, props); + + // then + assertThat(query.getIds()).doesNotContain(Id.DEVICE_IP_V_6); + assertThat(query.getHid()).isEqualTo("&hid=i6:0%3A0%3A0%3A0%3A0%3A0%3A0%3A1"); + } + + @Test + public void shouldUrlEncodeHidValueWithSpecialCharacters() { + // given + final OptableTargetingProperties props = givenProperties(null, "c"); + final List ids = List.of(Id.of("c", "a b&c=d+e/f")); + + // when + final Query query = QueryBuilder.build(ids, optableAttributes, props); + + // then + assertThat(query.getHid()).isEqualTo("&hid=c:a+b%26c%3Dd%2Be%2Ff"); + } + + @Test + public void shouldLeaveHidValueUnchangedForAlphanumericValue() { + // given + final OptableTargetingProperties props = givenProperties(null, "c"); + final List ids = List.of(Id.of("c", "abc123")); + + // when + final Query query = QueryBuilder.build(ids, optableAttributes, props); + + // then + assertThat(query.getHid()).isEqualTo("&hid=c:abc123"); + } + + @Test + public void shouldNotBuildHidWhenNoMatch() { + // given + final OptableTargetingProperties props = givenProperties(null, "nonexistent"); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, optableAttributes, props); + + // then + assertThat(query.getHid()).isEqualTo(""); + } + + @Test + public void shouldNotBuildHidWhenHidPrefixesNotConfigured() { + // given + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, optableAttributes, properties()); + + // then + assertThat(query.getHid()).isEqualTo(""); + } + + @Test + public void shouldAppendBundleAndVerWhenAppHasBoth() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .app(App.of("com.example.app", "1.2.3")) + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); + + // then + assertThat(query).contains("&bundle=com.example.app", "&ver=1.2.3"); + } + + @Test + public void shouldAppendBundleOnlyWhenVerIsEmpty() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .app(App.of("com.example.app", "")) + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); + + // then + assertThat(query).contains("&bundle=com.example.app"); + assertThat(query).doesNotContain("&ver="); + } + + @Test + public void shouldNotAppendBundleAndVerWhenBundleIsEmpty() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .app(App.of("", "1.2.3")) + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); + + // then + assertThat(query).doesNotContain("&bundle=", "&ver="); + } + + @Test + public void shouldNotAppendBundleAndVerWhenAppIsNull() { + // given + final OptableAttributes attributes = OptableAttributes.builder().build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); + + // then + assertThat(query).doesNotContain("&bundle=", "&ver="); + } + + @Test + public void shouldBuildHidAttributesWithBundleAndVerWhenAppIsPresent() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .app(App.of("com.example.app", "1.2.3")) + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, attributes, properties()); + + // then + assertThat(query.getHidAttributes()) + .isEqualTo("&bundle=com.example.app&ver=1.2.3"); + } + + @Test + public void shouldBuildHidAttributesWithBundleOnlyWhenVerIsEmpty() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .app(App.of("com.example.app", "")) + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, attributes, properties()); + + // then + assertThat(query.getHidAttributes()).isEqualTo("&bundle=com.example.app"); + } + + @Test + public void shouldNotBuildHidAttributesWithBundleWhenBundleIsEmpty() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .app(App.of("", "1.2.3")) + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, attributes, properties()); + + // then + assertThat(query.getHidAttributes()).doesNotContain("&bundle=", "&ver="); + } + + @Test + public void shouldNotBuildHidAttributesWithBundleWhenAppIsNull() { + // given + final OptableAttributes attributes = OptableAttributes.builder().build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, attributes, properties()); + + // then + assertThat(query.getHidAttributes()).isEmpty(); + } + + @Test + public void shouldBuildHidAttributesWithId5SignatureWhenPresent() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .id5Signature("signature") + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, attributes, properties()); + + // then + assertThat(query.getHidAttributes()).isEqualTo("&id5_signature=signature"); + } + + @Test + public void shouldNotBuildHidAttributesWithId5SignatureWhenNull() { + // given + final OptableAttributes attributes = OptableAttributes.builder().build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, attributes, properties()); + + // then + assertThat(query.getHidAttributes()).doesNotContain("&id5_signature="); + } + + @Test + public void shouldIncludeHidAttributesInToQueryString() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .app(App.of("com.example.app", "1.2.3")) + .id5Signature("signature") + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final String queryString = QueryBuilder.build(ids, attributes, properties()).toQueryString(); + + // then + assertThat(queryString).endsWith("&bundle=com.example.app&ver=1.2.3&id5_signature=signature"); + // they live in hidAttributes so that they take part in the cache key, and must not + // also be emitted from buildAttributesString + assertThat(queryString.split("&bundle=", -1)).hasSize(2); + assertThat(queryString.split("&ver=", -1)).hasSize(2); + assertThat(queryString.split("&id5_signature=", -1)).hasSize(2); + } + + @Test + public void shouldTrimWhitespaceAroundHidPrefixes() { + // given + final List ids = List.of(Id.of(Id.EMAIL, "email"), Id.of(Id.PHONE, "phone")); + // when + final Query query = QueryBuilder.build( + ids, OptableAttributes.builder().build(), givenProperties(idPrefixOrder, " e , p ")); + // then + assertThat(query.getHid()).isEqualTo("&hid=e:email&hid=p:phone"); + } + + @Test + public void shouldAppendBundleAndVerToHidAttributesWithSpecialCharacters() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .app(App.of("com.example app", "1.2 3")) + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, attributes, properties()); + + // then + assertThat(query.getHidAttributes()) + .isEqualTo("&bundle=com.example+app&ver=1.2+3"); + } + + @Test + public void shouldAppendId5SignatureToHidAttributesWithSpecialCharacters() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .id5Signature("a b&c=d") + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final Query query = QueryBuilder.build(ids, attributes, properties()); + + // then + assertThat(query.getHidAttributes()).isEqualTo("&id5_signature=a+b%26c%3Dd"); + } + + @Test + public void shouldAppendId5SignatureWhenPresent() { + // given + final OptableAttributes attributes = OptableAttributes.builder() + .id5Signature("signature") + .build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); + + // then + assertThat(query).contains("&id5_signature=signature"); + } + + @Test + public void shouldNotAppendId5SignatureWhenNull() { + // given + final OptableAttributes attributes = OptableAttributes.builder().build(); + final List ids = List.of(Id.of(Id.EMAIL, "email")); + + // when + final String query = QueryBuilder.build(ids, attributes, properties()).toQueryString(); + + // then + assertThat(query).doesNotContain("&id5_signature="); + } + private OptableAttributes givenOptableAttributes() { return OptableAttributes.builder() .timeout(100L) @@ -194,4 +521,11 @@ private OptableAttributes givenOptableAttributes() { .gdprConsent("tcf") .build(); } + + private static OptableTargetingProperties givenProperties(String idPrefixOrder, String hidPrefixes) { + final OptableTargetingProperties properties = new OptableTargetingProperties(); + properties.setIdPrefixOrder(idPrefixOrder); + properties.setHidPrefixes(hidPrefixes); + return properties; + } } diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/APIClientImplTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/APIClientImplTest.java index bcf913351ce..3b80f33690b 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/APIClientImplTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/APIClientImplTest.java @@ -40,7 +40,7 @@ public class APIClientImplTest extends BaseOptableTest { @BeforeEach public void setUp() { - target = new APIClientImpl("http://endpoint.optable.com", httpClient, jacksonMapper, 100); + target = new APIClientImpl("https://endpoint.optable.com", httpClient, jacksonMapper, 100); } @Test @@ -140,7 +140,7 @@ public void shouldNotFailWhenInternalErrorOccurs() { @Test public void shouldUseAuthorizationHeaderIfApiKeyIsPresent() { // given - target = new APIClientImpl("http://endpoint.optable.com", httpClient, jacksonMapper, 10); + target = new APIClientImpl("https://endpoint.optable.com", httpClient, jacksonMapper, 10); when(httpClient.get(any(), any(), anyLong())) .thenReturn(Future.succeededFuture(givenFailHttpResponse( @@ -162,7 +162,7 @@ public void shouldUseAuthorizationHeaderIfApiKeyIsPresent() { public void shouldBuildApiUrlByReplacingTenantAndOriginMacros() { // given target = new APIClientImpl( - "http://endpoint.optable.com?t={TENANT}&o={ORIGIN}", + "https://endpoint.optable.com?t={TENANT}&o={ORIGIN}", httpClient, jacksonMapper, 10); @@ -179,7 +179,7 @@ public void shouldBuildApiUrlByReplacingTenantAndOriginMacros() { final ArgumentCaptor endpointCaptor = ArgumentCaptor.forClass(String.class); verify(httpClient).get(endpointCaptor.capture(), any(), anyLong()); assertThat(endpointCaptor.getValue()) - .isEqualTo("http://endpoint.optable.com?t=accountId&o=origin?query"); + .isEqualTo("https://endpoint.optable.com?t=accountId&o=origin?query"); assertThat(result.result()).isNull(); } diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/CachedAPIClientTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/CachedAPIClientTest.java index e624fa56a8c..db7542c3b32 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/CachedAPIClientTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/CachedAPIClientTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.execution.timeout.Timeout; @@ -13,6 +14,8 @@ import org.prebid.server.hooks.modules.optable.targeting.v1.BaseOptableTest; import org.prebid.server.hooks.modules.optable.targeting.v1.core.Cache; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -170,4 +173,90 @@ public void shouldCacheEmptyResultWhenCircuitBreakerIsOn() { assertThat(result.getAudience()).isNull(); verify(cache, times(1)).put(any(), eq(targetingResult.result()), anyInt()); } + + @Test + public void shouldIncludeHidInCacheKey() { + // given + final Query query = Query.of("&id=e%3Aemail", "&hid=c:234", "&gdpr=1", ""); + final ArgumentCaptor keyCaptor = ArgumentCaptor.forClass(String.class); + when(cache.get(keyCaptor.capture())).thenReturn(Future.succeededFuture(givenTargetingResult())); + + // when + target.getTargeting( + givenOptableTargetingProperties(true), + query, + List.of("8.8.8.8"), + "user agent", + timeout); + + // then + final String key = keyCaptor.getValue(); + assertThat(key).contains(URLEncoder.encode("&hid=c:234", StandardCharsets.UTF_8)); + } + + @Test + public void shouldIncludeHidAttributesInCacheKey() { + // given + final Query query = Query.of("&id=e%3Aemail", "", "&gdpr=1", "&bundle=com.example.app"); + final ArgumentCaptor keyCaptor = ArgumentCaptor.forClass(String.class); + when(cache.get(keyCaptor.capture())).thenReturn(Future.succeededFuture(givenTargetingResult())); + + // when + target.getTargeting( + givenOptableTargetingProperties(true), + query, + List.of("8.8.8.8"), + "user agent", + timeout); + + // then + final String key = keyCaptor.getValue(); + assertThat(key).contains(URLEncoder.encode("&bundle=com.example.app", StandardCharsets.UTF_8)); + } + + @Test + public void shouldBuildCacheKeyWithAllComponents() { + // given + final Query query = Query.of("&id=e%3Aemail", "&hid=c:234", "&gdpr=1", "&id5_signature=sig"); + final ArgumentCaptor keyCaptor = ArgumentCaptor.forClass(String.class); + when(cache.get(keyCaptor.capture())).thenReturn(Future.succeededFuture(givenTargetingResult())); + + // when + target.getTargeting( + givenOptableTargetingProperties("key", "accountId", "origin", true), + query, + List.of("8.8.8.8"), + "user agent", + timeout); + + // then + final String key = keyCaptor.getValue(); + assertThat(key).isEqualTo( + "accountId:origin:8.8.8.8:" + + URLEncoder.encode("&id=e%3Aemail", StandardCharsets.UTF_8) + + ":" + + URLEncoder.encode("&hid=c:234", StandardCharsets.UTF_8) + + ":" + + URLEncoder.encode("&id5_signature=sig", StandardCharsets.UTF_8)); + } + + @Test + public void shouldUseNullInCacheKeyWhenHidIsNull() { + // given + final Query query = Query.of("&id=e%3Aemail", null, "&gdpr=1", null); + final ArgumentCaptor keyCaptor = ArgumentCaptor.forClass(String.class); + when(cache.get(keyCaptor.capture())).thenReturn(Future.succeededFuture(givenTargetingResult())); + + // when + target.getTargeting( + givenOptableTargetingProperties(true), + query, + List.of("8.8.8.8"), + "user agent", + timeout); + + // then + final String key = keyCaptor.getValue(); + assertThat(key).endsWith(":null:null"); + } } diff --git a/extra/modules/optable-targeting/src/test/resources/error_response.json b/extra/modules/optable-targeting/src/test/resources/error_response.json index 4250099e7ba..63198fe03c6 100644 --- a/extra/modules/optable-targeting/src/test/resources/error_response.json +++ b/extra/modules/optable-targeting/src/test/resources/error_response.json @@ -1 +1,3 @@ -{"details": "Error message"} +{ + "details": "Error message" +} diff --git a/extra/modules/optable-targeting/src/test/resources/targeting_response.json b/extra/modules/optable-targeting/src/test/resources/targeting_response.json index a5959de45c9..120cb16853e 100644 --- a/extra/modules/optable-targeting/src/test/resources/targeting_response.json +++ b/extra/modules/optable-targeting/src/test/resources/targeting_response.json @@ -1,6 +1,5 @@ { "user": [ - ], "audience": [ { diff --git a/extra/modules/pb-ortb2-blocking/pom.xml b/extra/modules/pb-ortb2-blocking/pom.xml index e011878d97a..60db961b839 100644 --- a/extra/modules/pb-ortb2-blocking/pom.xml +++ b/extra/modules/pb-ortb2-blocking/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT pb-ortb2-blocking diff --git a/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReader.java b/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReader.java index 1296b3e50c7..87d190f449f 100644 --- a/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReader.java +++ b/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/AccountConfigReader.java @@ -440,13 +440,13 @@ private static BlockedAttributes toBlockedAttributes(Result> badv, || battr.hasValue() ? BlockedAttributes.builder() - .badv(badv.getValue()) - .bcat(bcat.getValue()) - .cattaxComplement(cattaxComplement.getValue()) - .bapp(bapp.getValue()) - .btype(btype.getValue()) - .battr(battr.getValue()) - .build() + .badv(badv.getValue()) + .bcat(bcat.getValue()) + .cattaxComplement(cattaxComplement.getValue()) + .bapp(bapp.getValue()) + .btype(btype.getValue()) + .battr(battr.getValue()) + .build() : null; } diff --git a/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/BidsBlocker.java b/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/BidsBlocker.java index f34355dc9e4..6e0c33ac9f0 100644 --- a/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/BidsBlocker.java +++ b/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/BidsBlocker.java @@ -5,9 +5,9 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.prebid.server.auction.model.BidRejection; import org.prebid.server.auction.model.BidRejectionReason; import org.prebid.server.auction.model.Rejection; -import org.prebid.server.auction.model.BidRejection; import org.prebid.server.auction.versionconverter.OrtbVersion; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.hooks.modules.ortb2.blocking.core.exception.InvalidAccountConfigurationException; @@ -157,7 +157,7 @@ private AttributeCheckResult checkCattax(BidderBid bidderBid, ResponseB return checkAttributeComplement( cattax, blockingConfig.getCattax(), - ObjectUtils.defaultIfNull( + ObjectUtils.getIfNull( blockedAttributeValues(BlockedAttributes::getCattaxComplement), DEFAULT_BLOCKED_CATTAX_COMPLEMENT)); } diff --git a/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdater.java b/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdater.java index 78744e7c07f..b5d83817620 100644 --- a/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdater.java +++ b/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdater.java @@ -107,9 +107,9 @@ private static Banner updateBanner(Banner banner, List btype, List battr) { final List existingBattr = video.getBattr(); return CollectionUtils.isEmpty(existingBattr) ? video.toBuilder() - .battr(battr) - .build() + .battr(battr) + .build() : video; } @@ -134,8 +134,8 @@ private static Audio updateAudio(Audio audio, List battr) { final List existingBattr = audio.getBattr(); return CollectionUtils.isEmpty(existingBattr) ? audio.toBuilder() - .battr(battr) - .build() + .battr(battr) + .build() : audio; } } diff --git a/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/v1/Ortb2BlockingRawBidderResponseHook.java b/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/v1/Ortb2BlockingRawBidderResponseHook.java index 015c653250d..3ded66875b0 100644 --- a/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/v1/Ortb2BlockingRawBidderResponseHook.java +++ b/extra/modules/pb-ortb2-blocking/src/main/java/org/prebid/server/hooks/modules/ortb2/blocking/v1/Ortb2BlockingRawBidderResponseHook.java @@ -56,7 +56,7 @@ public Future> call(BidderResponsePayloa .create( bidderResponsePayload.bids(), bidder, - ObjectUtils.defaultIfNull(moduleContext.ortbVersionOf(bidder), OrtbVersion.ORTB_2_5), + ObjectUtils.getIfNull(moduleContext.ortbVersionOf(bidder), OrtbVersion.ORTB_2_5), invocationContext.accountConfig(), moduleContext.blockedAttributesFor(bidder), invocationContext.debugEnabled()) diff --git a/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdaterTest.java b/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdaterTest.java index 1f03f82edb1..f3852fdc1fb 100644 --- a/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdaterTest.java +++ b/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/RequestUpdaterTest.java @@ -246,7 +246,7 @@ public void shouldNotChangeImpWhenNoBlockedBannerTypeAndBlockedBannerAttrForImp( // when and then final BidRequest updatedRequest = updater.update(request); assertThat(updatedRequest.getImp()).hasSize(1); - assertThat(updatedRequest.getImp().get(0)).isSameAs(imp); + assertThat(updatedRequest.getImp().getFirst()).isSameAs(imp); } @Test @@ -264,7 +264,7 @@ public void shouldNotChangeImpWhenNoBlockedVideoAttrForImp() { // when and then final BidRequest updatedRequest = updater.update(request); assertThat(updatedRequest.getImp()).hasSize(1); - assertThat(updatedRequest.getImp().get(0)).isSameAs(imp); + assertThat(updatedRequest.getImp().getFirst()).isSameAs(imp); } @Test @@ -282,7 +282,7 @@ public void shouldNotChangeImpWhenNoBlockedAudioAttrForImp() { // when and then final BidRequest updatedRequest = updater.update(request); assertThat(updatedRequest.getImp()).hasSize(1); - assertThat(updatedRequest.getImp().get(0)).isSameAs(imp); + assertThat(updatedRequest.getImp().getFirst()).isSameAs(imp); } @Test diff --git a/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/config/Attribute.java b/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/config/Attribute.java index 4e59baac6d4..c7984c3bae4 100644 --- a/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/config/Attribute.java +++ b/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/core/config/Attribute.java @@ -36,8 +36,8 @@ public Map getProperties() { properties.computeIfAbsent("action-overrides", key -> actionOverrides != null ? actionOverrides.toBuilder() - .field(field) - .build() + .field(field) + .build() : null); return properties; diff --git a/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/v1/Ortb2BlockingRawBidderResponseHookTest.java b/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/v1/Ortb2BlockingRawBidderResponseHookTest.java index 9c4d20693a6..9c12646aaee 100644 --- a/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/v1/Ortb2BlockingRawBidderResponseHookTest.java +++ b/extra/modules/pb-ortb2-blocking/src/test/java/org/prebid/server/hooks/modules/ortb2/blocking/v1/Ortb2BlockingRawBidderResponseHookTest.java @@ -197,10 +197,10 @@ public void shouldReturnResultWithPayloadUpdateAndAnalyticsTags() { .build())))))); assertThat(invocationResult.rejections()).containsOnly(entry("bidder1", List.of( - BidRejection.of(bid1, - RESPONSE_REJECTED_ADVERTISER_BLOCKED), - BidRejection.of(bid(bid -> bid.id("bidId2").adomain(singletonList("domain2.com"))), - RESPONSE_REJECTED_ADVERTISER_BLOCKED)))); + BidRejection.of(bid1, + RESPONSE_REJECTED_ADVERTISER_BLOCKED), + BidRejection.of(bid(bid -> bid.id("bidId2").adomain(singletonList("domain2.com"))), + RESPONSE_REJECTED_ADVERTISER_BLOCKED)))); } @Test diff --git a/extra/modules/pb-request-correction/pom.xml b/extra/modules/pb-request-correction/pom.xml index 00c00582358..dacba5365c0 100644 --- a/extra/modules/pb-request-correction/pom.xml +++ b/extra/modules/pb-request-correction/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT pb-request-correction diff --git a/extra/modules/pb-request-correction/src/main/java/org/prebid/server/hooks/modules/pb/request/correction/core/correction/interstitial/InterstitialCorrectionProducer.java b/extra/modules/pb-request-correction/src/main/java/org/prebid/server/hooks/modules/pb/request/correction/core/correction/interstitial/InterstitialCorrectionProducer.java index c9bd1995867..9d8116d752e 100644 --- a/extra/modules/pb-request-correction/src/main/java/org/prebid/server/hooks/modules/pb/request/correction/core/correction/interstitial/InterstitialCorrectionProducer.java +++ b/extra/modules/pb-request-correction/src/main/java/org/prebid/server/hooks/modules/pb/request/correction/core/correction/interstitial/InterstitialCorrectionProducer.java @@ -3,7 +3,7 @@ import com.iab.openrtb.request.App; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.hooks.modules.pb.request.correction.core.config.model.Config; import org.prebid.server.hooks.modules.pb.request.correction.core.correction.Correction; import org.prebid.server.hooks.modules.pb.request.correction.core.correction.CorrectionProducer; @@ -53,11 +53,11 @@ private static boolean isPrebidMobile(App app) { .map(ExtAppPrebid::getSource) .orElse(null); - return StringUtils.equalsIgnoreCase(source, PREBID_MOBILE); + return Strings.CI.equals(source, PREBID_MOBILE); } private static boolean isAndroid(App app) { - return StringUtils.containsIgnoreCase(app.getBundle(), ANDROID); + return Strings.CI.contains(app.getBundle(), ANDROID); } private static boolean isApplicableVersion(App app) { diff --git a/extra/modules/pb-request-correction/src/main/java/org/prebid/server/hooks/modules/pb/request/correction/core/correction/useragent/UserAgentCorrectionProducer.java b/extra/modules/pb-request-correction/src/main/java/org/prebid/server/hooks/modules/pb/request/correction/core/correction/useragent/UserAgentCorrectionProducer.java index c5010553f5a..a7d88e7b99b 100644 --- a/extra/modules/pb-request-correction/src/main/java/org/prebid/server/hooks/modules/pb/request/correction/core/correction/useragent/UserAgentCorrectionProducer.java +++ b/extra/modules/pb-request-correction/src/main/java/org/prebid/server/hooks/modules/pb/request/correction/core/correction/useragent/UserAgentCorrectionProducer.java @@ -4,6 +4,7 @@ import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.hooks.modules.pb.request.correction.core.config.model.Config; import org.prebid.server.hooks.modules.pb.request.correction.core.correction.Correction; import org.prebid.server.hooks.modules.pb.request.correction.core.correction.CorrectionProducer; @@ -42,7 +43,7 @@ private static boolean isPrebidMobile(App app) { .map(ExtAppPrebid::getSource) .orElse(null); - return StringUtils.equalsIgnoreCase(source, PREBID_MOBILE); + return Strings.CI.equals(source, PREBID_MOBILE); } private static boolean isApplicableVersion(App app) { diff --git a/extra/modules/pb-response-correction/pom.xml b/extra/modules/pb-response-correction/pom.xml index da76a6b4a5b..85f4946e0dd 100644 --- a/extra/modules/pb-response-correction/pom.xml +++ b/extra/modules/pb-response-correction/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT pb-response-correction diff --git a/extra/modules/pb-richmedia-filter/README.md b/extra/modules/pb-richmedia-filter/README.md index 11fc42c5a3f..d1d5f5d5cd9 100644 --- a/extra/modules/pb-richmedia-filter/README.md +++ b/extra/modules/pb-richmedia-filter/README.md @@ -6,6 +6,7 @@ The filtering logic can be provided by enabling the hook. ## Configuration To start using current module you have to enable module and add ``pb-richmedia-filter-all-processed-bid-responses-hook`` into hooks execution plan inside your yaml file: + ```yaml hooks: pb-richmedia-filter: @@ -33,6 +34,7 @@ hooks: } } ``` + And configure ## List of module configuration options diff --git a/extra/modules/pb-richmedia-filter/pom.xml b/extra/modules/pb-richmedia-filter/pom.xml index af87c7df21a..e8943e8a5f1 100644 --- a/extra/modules/pb-richmedia-filter/pom.xml +++ b/extra/modules/pb-richmedia-filter/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT pb-richmedia-filter diff --git a/extra/modules/pb-richmedia-filter/src/main/java/org/prebid/server/hooks/modules/pb/richmedia/filter/core/BidResponsesMraidFilter.java b/extra/modules/pb-richmedia-filter/src/main/java/org/prebid/server/hooks/modules/pb/richmedia/filter/core/BidResponsesMraidFilter.java index b8494d1103a..cdc036541e8 100644 --- a/extra/modules/pb-richmedia-filter/src/main/java/org/prebid/server/hooks/modules/pb/richmedia/filter/core/BidResponsesMraidFilter.java +++ b/extra/modules/pb-richmedia-filter/src/main/java/org/prebid/server/hooks/modules/pb/richmedia/filter/core/BidResponsesMraidFilter.java @@ -1,7 +1,7 @@ package org.prebid.server.hooks.modules.pb.richmedia.filter.core; import com.iab.openrtb.response.Bid; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.model.BidRejectionReason; import org.prebid.server.auction.model.BidderResponse; import org.prebid.server.bidder.model.BidderBid; @@ -32,7 +32,7 @@ public MraidFilterResult filterByPattern(String mraidScriptPattern, final BidderSeatBid seatBid = bidderResponse.getSeatBid(); final List originalBids = seatBid.getBids(); final Map> bidsMap = originalBids.stream().collect( - Collectors.groupingBy(bid -> StringUtils.contains(bid.getBid().getAdm(), mraidScriptPattern))); + Collectors.groupingBy(bid -> Strings.CS.contains(bid.getBid().getAdm(), mraidScriptPattern))); final List validBids = bidsMap.getOrDefault(false, Collections.emptyList()); final List invalidBids = bidsMap.getOrDefault(true, Collections.emptyList()); diff --git a/extra/modules/pb-richmedia-filter/src/main/java/org/prebid/server/hooks/modules/pb/richmedia/filter/v1/PbRichmediaFilterAllProcessedBidResponsesHook.java b/extra/modules/pb-richmedia-filter/src/main/java/org/prebid/server/hooks/modules/pb/richmedia/filter/v1/PbRichmediaFilterAllProcessedBidResponsesHook.java index dcec0dfa3ff..630a2e94703 100644 --- a/extra/modules/pb-richmedia-filter/src/main/java/org/prebid/server/hooks/modules/pb/richmedia/filter/v1/PbRichmediaFilterAllProcessedBidResponsesHook.java +++ b/extra/modules/pb-richmedia-filter/src/main/java/org/prebid/server/hooks/modules/pb/richmedia/filter/v1/PbRichmediaFilterAllProcessedBidResponsesHook.java @@ -5,9 +5,9 @@ import io.vertx.core.Future; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; +import org.prebid.server.auction.model.BidRejection; import org.prebid.server.auction.model.BidderResponse; import org.prebid.server.auction.model.Rejection; -import org.prebid.server.auction.model.BidRejection; import org.prebid.server.hooks.execution.v1.InvocationResultImpl; import org.prebid.server.hooks.execution.v1.analytics.ActivityImpl; import org.prebid.server.hooks.execution.v1.analytics.AppliedToImpl; diff --git a/extra/modules/pb-richmedia-filter/src/test/java/org/prebid/server/hooks/modules/pb/richmedia/filter/v1/PbRichmediaFilterAllProcessedBidResponsesHookTest.java b/extra/modules/pb-richmedia-filter/src/test/java/org/prebid/server/hooks/modules/pb/richmedia/filter/v1/PbRichmediaFilterAllProcessedBidResponsesHookTest.java index 0465336a65a..d84b74efd72 100644 --- a/extra/modules/pb-richmedia-filter/src/test/java/org/prebid/server/hooks/modules/pb/richmedia/filter/v1/PbRichmediaFilterAllProcessedBidResponsesHookTest.java +++ b/extra/modules/pb-richmedia-filter/src/test/java/org/prebid/server/hooks/modules/pb/richmedia/filter/v1/PbRichmediaFilterAllProcessedBidResponsesHookTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.prebid.server.auction.model.BidderResponse; import org.prebid.server.auction.model.BidRejection; +import org.prebid.server.auction.model.BidderResponse; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderSeatBid; import org.prebid.server.hooks.execution.v1.analytics.ActivityImpl; diff --git a/extra/modules/pb-rule-engine/pom.xml b/extra/modules/pb-rule-engine/pom.xml index 2ba24bb41bf..929223b6a1b 100644 --- a/extra/modules/pb-rule-engine/pom.xml +++ b/extra/modules/pb-rule-engine/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT pb-rule-engine diff --git a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/config/RuleParser.java b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/config/RuleParser.java index bd10c138622..3fc587374e6 100644 --- a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/config/RuleParser.java +++ b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/config/RuleParser.java @@ -67,7 +67,7 @@ public Future parseForAccount(String accountId, ObjectNode config) } parseConfig(accountId, config); - return Future.succeededFuture(ObjectUtils.defaultIfNull(cachedRule, PerStageRule.noOp())); + return Future.succeededFuture(ObjectUtils.getIfNull(cachedRule, PerStageRule.noOp())); } private Instant getConfigTimestamp(ObjectNode config) { diff --git a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/result/functions/filter/FilterBiddersFunction.java b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/result/functions/filter/FilterBiddersFunction.java index 8e2887c4ed8..621a599fc24 100644 --- a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/result/functions/filter/FilterBiddersFunction.java +++ b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/result/functions/filter/FilterBiddersFunction.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.model.BidRejectionReason; import org.prebid.server.bidder.BidderCatalog; import org.prebid.server.cookie.UidsCookie; @@ -55,13 +55,13 @@ public RuleResult apply(ResultFunctionArguments seatNonBid = new ArrayList<>(); for (Imp imp : bidRequest.getImp()) { - if (granularity instanceof Granularity.Imp(String impId) && !StringUtils.equals(impId, imp.getId())) { + if (granularity instanceof Granularity.Imp(String impId) && !Strings.CS.equals(impId, imp.getId())) { updatedImps.add(imp); continue; } switch (filterBidders(imp, config.getBidders(), ifSyncedId, uidsCookie)) { - case FilterBiddersResult.NoAction noAction -> updatedImps.add(imp); + case FilterBiddersResult.NoAction _ -> updatedImps.add(imp); case FilterBiddersResult.Reject reject -> seatNonBid.addAll(toSeatNonBid(imp.getId(), reject.bidders(), rejectionReason)); diff --git a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/AdUnitCodeFunction.java b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/AdUnitCodeFunction.java index 165293f8b71..a00015d9ad9 100644 --- a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/AdUnitCodeFunction.java +++ b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/AdUnitCodeFunction.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import org.apache.commons.collections4.ListUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.hooks.modules.rule.engine.core.request.Granularity; import org.prebid.server.hooks.modules.rule.engine.core.request.RequestRuleContext; import org.prebid.server.hooks.modules.rule.engine.core.request.schema.functions.util.AdUnitCodeUtils; @@ -22,7 +22,7 @@ public String extract(SchemaFunctionArguments ar final BidRequest bidRequest = arguments.getOperand(); return ListUtils.emptyIfNull(bidRequest.getImp()).stream() - .filter(imp -> StringUtils.equals(imp.getId(), impId)) + .filter(imp -> Strings.CS.equals(imp.getId(), impId)) .findFirst() .flatMap(AdUnitCodeUtils::extractAdUnitCode) .orElse(UNDEFINED_RESULT); diff --git a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/AdUnitCodeInFunction.java b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/AdUnitCodeInFunction.java index 6b015863f97..a069522ee1e 100644 --- a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/AdUnitCodeInFunction.java +++ b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/AdUnitCodeInFunction.java @@ -5,7 +5,7 @@ import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; import org.apache.commons.collections4.ListUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.hooks.modules.rule.engine.core.request.Granularity; import org.prebid.server.hooks.modules.rule.engine.core.request.RequestRuleContext; import org.prebid.server.hooks.modules.rule.engine.core.request.schema.functions.util.AdUnitCodeUtils; @@ -32,7 +32,7 @@ public String extract(SchemaFunctionArguments ar final BidRequest bidRequest = arguments.getOperand(); final Imp adUnit = ListUtils.emptyIfNull(bidRequest.getImp()).stream() - .filter(imp -> StringUtils.equals(imp.getId(), impId)) + .filter(imp -> Strings.CS.equals(imp.getId(), impId)) .findFirst() .orElseThrow(() -> new IllegalStateException( "Critical error in rules engine. Imp id of absent imp supplied")); diff --git a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/MediaTypeInFunction.java b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/MediaTypeInFunction.java index 547efb749ee..302a500f006 100644 --- a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/MediaTypeInFunction.java +++ b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/request/schema/functions/MediaTypeInFunction.java @@ -5,7 +5,7 @@ import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; import org.apache.commons.collections4.ListUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.hooks.modules.rule.engine.core.request.Granularity; import org.prebid.server.hooks.modules.rule.engine.core.request.RequestRuleContext; import org.prebid.server.hooks.modules.rule.engine.core.rules.schema.SchemaFunction; @@ -30,7 +30,7 @@ public String extract(SchemaFunctionArguments ar final BidRequest bidRequest = arguments.getOperand(); final Imp adUnit = ListUtils.emptyIfNull(bidRequest.getImp()).stream() - .filter(imp -> StringUtils.equals(imp.getId(), impId)) + .filter(imp -> Strings.CS.equals(imp.getId(), impId)) .findFirst() .orElseThrow(() -> new IllegalStateException( "Critical error in rules engine. Imp id of absent imp supplied")); diff --git a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/rules/schema/functions/PercentFunction.java b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/rules/schema/functions/PercentFunction.java index 2d03ce5e6e0..eb5339bb71f 100644 --- a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/rules/schema/functions/PercentFunction.java +++ b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/rules/schema/functions/PercentFunction.java @@ -19,7 +19,7 @@ public class PercentFunction implements SchemaFunction { @Override public String extract(SchemaFunctionArguments arguments) { - final int resolvedUpperBound = Math.min(Math.max(arguments.getConfig().get(PCT_FIELD).asInt(), 0), 100); + final int resolvedUpperBound = Math.clamp(arguments.getConfig().get(PCT_FIELD).asInt(), 0, 100); return Boolean.toString(random.nextInt(100) < resolvedUpperBound); } diff --git a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/rules/tree/RuleTree.java b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/rules/tree/RuleTree.java index 6473bd5620f..c68bedce5a2 100644 --- a/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/rules/tree/RuleTree.java +++ b/extra/modules/pb-rule-engine/src/main/java/org/prebid/server/hooks/modules/rule/engine/core/rules/tree/RuleTree.java @@ -31,7 +31,7 @@ public LookupResult lookup(List path) { case RuleNode.IntermediateNode node -> { final RuleNode result = node.next(pathPart); matches.add(result == null ? WILDCARD_MATCHER : pathPart); - yield ObjectUtils.defaultIfNull(result, node.next(WILDCARD_MATCHER)); + yield ObjectUtils.getIfNull(result, node.next(WILDCARD_MATCHER)); } case RuleNode.LeafNode ignored -> throw new IllegalArgumentException("Argument count mismatch"); diff --git a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/config/AccountConfigParserTest.java b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/config/AccountConfigParserTest.java index fe7a33b5a56..1483b9a613c 100644 --- a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/config/AccountConfigParserTest.java +++ b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/config/AccountConfigParserTest.java @@ -49,7 +49,7 @@ public void parseShouldReturnNoOpConfigWhenEnabledIsFalse() { @Test public void parseShouldParseRuleForEachSupportedStage() { // given - final Rule rule = (Rule) mock(Rule.class); + final Rule rule = mock(); given(processedAuctionRequestStageParser.parse(any())).willReturn(rule); // when and then diff --git a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/config/StageConfigParserTest.java b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/config/StageConfigParserTest.java index 79875a16a0e..4937c3eeb5a 100644 --- a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/config/StageConfigParserTest.java +++ b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/config/StageConfigParserTest.java @@ -25,7 +25,6 @@ import org.prebid.server.hooks.modules.rule.engine.core.rules.schema.Schema; import org.prebid.server.hooks.modules.rule.engine.core.rules.schema.SchemaFunction; import org.prebid.server.hooks.modules.rule.engine.core.rules.schema.SchemaFunctionHolder; -import org.prebid.server.hooks.modules.rule.engine.core.rules.tree.RuleTreeFactory; import org.prebid.server.hooks.modules.rule.engine.core.util.WeightedEntry; import org.prebid.server.hooks.modules.rule.engine.core.util.WeightedList; @@ -64,9 +63,6 @@ public class StageConfigParserTest { @Mock(strictness = LENIENT) private Rule matchingRule; - @Mock(strictness = LENIENT) - private RuleTreeFactory ruleTreeFactory; - @BeforeEach public void setUp() { target = new StageConfigParser<>( @@ -150,7 +146,7 @@ public void parseShouldCombineMatchingRuleWithDefaultUnderSameModelGroup() { given(stageSpecification.schemaFunctionByName("function1")).willReturn(schemaFunction); given(stageSpecification.resultFunctionByName("function2")).willReturn(resultFunction); - final ResultFunction secondResultFunction = mock(ResultFunction.class); + final ResultFunction secondResultFunction = mock(); given(stageSpecification.resultFunctionByName("function3")).willReturn(secondResultFunction); given(conditionalRuleFactory.create(any(), any(), any(), any())).willReturn(matchingRule); diff --git a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/CompositeRuleTest.java b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/CompositeRuleTest.java index a53fd44a31b..a145f8cfa9e 100644 --- a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/CompositeRuleTest.java +++ b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/CompositeRuleTest.java @@ -27,14 +27,14 @@ public class CompositeRuleTest { @Test public void processShouldAccumulateResultFromAllSubrules() { // given - final Rule firstRule = (Rule) mock(Rule.class); + final Rule firstRule = mock(); given(firstRule.process(any(), any())).willAnswer(invocationOnMock -> RuleResult.of( invocationOnMock.getArgument(0), RuleAction.UPDATE, TagsImpl.of(singletonList(ActivityImpl.of("firstActivity", "success", emptyList()))), singletonList(SeatNonBid.of("firstSeat", singletonList(NonBid.of("1", BidRejectionReason.NO_BID)))))); - final Rule secondRule = (Rule) mock(Rule.class); + final Rule secondRule = mock(); given(secondRule.process(any(), any())).willAnswer(invocationOnMock -> RuleResult.of( invocationOnMock.getArgument(0), RuleAction.UPDATE, diff --git a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/DefaultActionRuleTest.java b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/DefaultActionRuleTest.java index 2a9fa1ceec4..f142e0afadb 100644 --- a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/DefaultActionRuleTest.java +++ b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/DefaultActionRuleTest.java @@ -35,8 +35,7 @@ public void processShouldAccumulateResultFromAllRuleActions() { final Object context = new Object(); final ObjectNode firstConfig = MAPPER.createObjectNode().set("config", TextNode.valueOf("test")); - final ResultFunction firstFunction = - (ResultFunction) mock(ResultFunction.class); + final ResultFunction firstFunction = mock(); given(firstFunction.apply(any())).willAnswer(invocationOnMock -> RuleResult.of( ((ResultFunctionArguments) invocationOnMock.getArgument(0)).getOperand(), RuleAction.UPDATE, @@ -44,8 +43,7 @@ public void processShouldAccumulateResultFromAllRuleActions() { singletonList(SeatNonBid.of("firstSeat", singletonList(NonBid.of("1", BidRejectionReason.NO_BID)))))); final ObjectNode secondConfig = MAPPER.createObjectNode().set("config", TextNode.valueOf("anotherTest")); - final ResultFunction secondFunction = - (ResultFunction) mock(ResultFunction.class); + final ResultFunction secondFunction = mock(); given(secondFunction.apply(any())).willAnswer(invocationOnMock -> RuleResult.of( ((ResultFunctionArguments) invocationOnMock.getArgument(0)).getOperand(), RuleAction.UPDATE, diff --git a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/WeightedRuleTest.java b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/WeightedRuleTest.java index b9304f40b55..c20dc867b26 100644 --- a/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/WeightedRuleTest.java +++ b/extra/modules/pb-rule-engine/src/test/java/org/prebid/server/hooks/modules/rule/engine/core/rules/WeightedRuleTest.java @@ -15,8 +15,7 @@ public class WeightedRuleTest { @Test public void processShouldUtilizeRuleFromWeightedList() { // given - final WeightedList> ruleList = - (WeightedList>) mock(WeightedList.class); + final WeightedList> ruleList = mock(); final RuleResult stub = RuleResult.noAction(new Object()); given(ruleList.getForSeed(anyInt())).willReturn((left, right) -> stub); diff --git a/extra/modules/pom.xml b/extra/modules/pom.xml index b9844fcea43..fe979fd91f9 100644 --- a/extra/modules/pom.xml +++ b/extra/modules/pom.xml @@ -5,7 +5,7 @@ org.prebid prebid-server-aggregator - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT ../../extra/pom.xml diff --git a/extra/modules/wurfl-devicedetection/README.md b/extra/modules/wurfl-devicedetection/README.md index 2a5f9959c03..f9033329e9c 100644 --- a/extra/modules/wurfl-devicedetection/README.md +++ b/extra/modules/wurfl-devicedetection/README.md @@ -1,10 +1,10 @@ -## WURFL Device Enrichment Module +## WURFL Device Enrichment Module ### Overview -The **WURFL Device Enrichment Module** for Prebid Server enhances the OpenRTB 2.x payload -with comprehensive device detection data powered by **ScientiaMobile**’s WURFL device detection framework. -Thanks to WURFL's device knowledge, the module provides accurate and comprehensive device-related information, +The **WURFL Device Enrichment Module** for Prebid Server enhances the OpenRTB 2.x payload +with comprehensive device detection data powered by **ScientiaMobile**’s WURFL device detection framework. +Thanks to WURFL's device knowledge, the module provides accurate and comprehensive device-related information, enabling bidders to make better-informed targeting and optimization decisions. ### Key features @@ -12,28 +12,28 @@ enabling bidders to make better-informed targeting and optimization decisions. #### Device Field Enrichment: The WURFL module populates missing or empty fields in ortb2.device with the following data: - - **make**: Manufacturer of the device (e.g., "Apple", "Samsung"). - - **model**: Device model (e.g., "iPhone 14", "Galaxy S22"). - - **os**: Operating system (e.g., "iOS", "Android"). - - **osv**: Operating system version (e.g., "16.0", "12.0"). - - **h**: Screen height in pixels. - - **w**: Screen width in pixels. - - **ppi**: Screen pixels per inch (PPI). - - **pxratio**: Screen pixel density ratio. - - **devicetype**: Device type (e.g., mobile, tablet, desktop). - - **js**: Support for JavaScript, where 0 = no, 1 = yes - - **Note**: If these fields are already populated in the bid request, the module will not overwrite them. + +- **make**: Manufacturer of the device (e.g., "Apple", "Samsung"). +- **model**: Device model (e.g., "iPhone 14", "Galaxy S22"). +- **os**: Operating system (e.g., "iOS", "Android"). +- **osv**: Operating system version (e.g., "16.0", "12.0"). +- **h**: Screen height in pixels. +- **w**: Screen width in pixels. +- **ppi**: Screen pixels per inch (PPI). +- **pxratio**: Screen pixel density ratio. +- **devicetype**: Device type (e.g., mobile, tablet, desktop). +- **js**: Support for JavaScript, where 0 = no, 1 = yes +- **Note**: If these fields are already populated in the bid request, the module will not overwrite them. #### Publisher-Specific Enrichment: -Device enrichment is selectively enabled for publishers based on their account ID. +Device enrichment is selectively enabled for publishers based on their account ID. The module identifies publishers through the following fields: `site.publisher.id` (for web environments). `app.publisher.id` (for mobile app environments). `dooh.publisher.id` (for digital out-of-home environments). - ### Building WURFL Module with a licensed WURFL Onsite Java API In order to compile the WURFL module in the PBS Java server bundle using a licensed WURFL API, you must follow these steps: @@ -48,10 +48,9 @@ The repository is private and requires authentication: to set it up please check 2 - Change the `artfactId` value in the module's `pom.xml` from `wurfl-mock` to `wurfl` -3 - Update the `wurfl.version` property value to the latest WURFL Onsite Java API version available. +3 - Update the `wurfl.version` property value to the latest WURFL Onsite Java API version available. - -When the `pom.xml` references the mock API artifact, the module will compile a demo version that returns sample data, +When the `pom.xml` references the mock API artifact, the module will compile a demo version that returns sample data, allowing basic testing without an WURFL Onsite Java API license. 4 - Build the Prebid Server Java bundle with the WURFL module using the following command: @@ -124,7 +123,6 @@ hooks: | **`update-frequency-in-hours`** | Optional | Check interval (hours) for downloading updated wurfl file if modified. Defaults to 24 hours | | **`allowed-publisher-ids`** | Optional | List of publisher IDs permitted to use the module. Defaults to all publishers. | - A valid WURFL license must include all the required capabilities for device enrichment. ### Launching Prebid Server Java with the WURFL Module @@ -135,11 +133,11 @@ After configuring the module and successfully building the Prebid Server bundle, java -jar target/prebid-server-bundle.jar --spring.config.additional-location=sample/configs/prebid-config-with-wurfl.yaml ``` -This sample configuration contains the module hook basic configuration. +This sample configuration contains the module hook basic configuration. When the server starts, it downloads the WURFL file from the `wurfl-snapshot-url` and loads it into the module. -Sample request data for testing is available in the module's `sample` directory. Using the `auction` endpoint, +Sample request data for testing is available in the module's `sample` directory. Using the `auction` endpoint, you can observe WURFL-enriched device data in the response. ### Sample Response diff --git a/extra/modules/wurfl-devicedetection/pom.xml b/extra/modules/wurfl-devicedetection/pom.xml index 4a01dbf53fb..ba174f40f41 100644 --- a/extra/modules/wurfl-devicedetection/pom.xml +++ b/extra/modules/wurfl-devicedetection/pom.xml @@ -5,7 +5,7 @@ org.prebid.server.hooks.modules all-modules - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT wurfl-devicedetection diff --git a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/config/WURFLDeviceDetectionConfiguration.java b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/config/WURFLDeviceDetectionConfiguration.java index 809dad7b19a..3b214c84ae1 100644 --- a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/config/WURFLDeviceDetectionConfiguration.java +++ b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/config/WURFLDeviceDetectionConfiguration.java @@ -1,20 +1,20 @@ package org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.config; +import io.vertx.core.Vertx; +import org.prebid.server.execution.file.FileUtil; +import org.prebid.server.execution.file.syncer.FileSyncer; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.model.WURFLEngineUtils; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1.WURFLDeviceDetectionEntrypointHook; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1.WURFLDeviceDetectionModule; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1.WURFLDeviceDetectionRawAuctionRequestHook; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1.WURFLService; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import io.vertx.core.Vertx; -import org.prebid.server.execution.file.syncer.FileSyncer; +import org.prebid.server.json.JacksonMapper; import org.prebid.server.spring.config.model.FileSyncerProperties; import org.prebid.server.spring.config.model.HttpClientProperties; -import org.prebid.server.execution.file.FileUtil; -import org.prebid.server.json.JacksonMapper; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import java.nio.file.Path; import java.util.List; diff --git a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/resolver/HeadersResolver.java b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/resolver/HeadersResolver.java index a156b3a9b33..e9888b51027 100644 --- a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/resolver/HeadersResolver.java +++ b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/resolver/HeadersResolver.java @@ -3,10 +3,10 @@ import com.iab.openrtb.request.BrandVersion; import com.iab.openrtb.request.Device; import com.iab.openrtb.request.UserAgent; -import org.prebid.server.util.HttpUtil; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; +import org.prebid.server.util.HttpUtil; import java.util.Collections; import java.util.HashMap; diff --git a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/OrtbDeviceUpdater.java b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/OrtbDeviceUpdater.java index ec79b79049c..6f7da7bd988 100644 --- a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/OrtbDeviceUpdater.java +++ b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/OrtbDeviceUpdater.java @@ -1,17 +1,17 @@ package org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; -import org.prebid.server.hooks.execution.v1.auction.AuctionRequestPayloadImpl; import com.iab.openrtb.request.Device; import com.scientiamobile.wurfl.core.exc.CapabilityNotDefinedException; import com.scientiamobile.wurfl.core.exc.VirtualCapabilityNotDefinedException; +import org.prebid.server.hooks.execution.v1.auction.AuctionRequestPayloadImpl; +import org.prebid.server.hooks.v1.PayloadUpdate; +import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; +import org.prebid.server.json.JacksonMapper; import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.request.ExtDevice; -import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; -import org.prebid.server.hooks.v1.PayloadUpdate; import java.math.BigDecimal; import java.util.Objects; @@ -86,14 +86,8 @@ private Device update(Device ortbDevice) { } private static T tryUpdateField(T fromOrtbDevice, Supplier fromWurflDeviceSupplier) { - if (fromOrtbDevice != null) { - return fromOrtbDevice; - } + return fromOrtbDevice != null ? fromOrtbDevice : fromWurflDeviceSupplier.get(); - final T fromWurflDevice = fromWurflDeviceSupplier.get(); - return fromWurflDevice != null - ? fromWurflDevice - : fromOrtbDevice; } private String getWurflMake() { diff --git a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionEntrypointHook.java b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionEntrypointHook.java index 102d4a164b2..bb1384dbb4a 100644 --- a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionEntrypointHook.java +++ b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionEntrypointHook.java @@ -1,5 +1,7 @@ package org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1; +import io.vertx.core.Future; +import org.prebid.server.hooks.execution.v1.InvocationResultImpl; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.model.AuctionRequestHeadersContext; import org.prebid.server.hooks.v1.InvocationAction; import org.prebid.server.hooks.v1.InvocationContext; @@ -7,8 +9,6 @@ import org.prebid.server.hooks.v1.InvocationStatus; import org.prebid.server.hooks.v1.entrypoint.EntrypointHook; import org.prebid.server.hooks.v1.entrypoint.EntrypointPayload; -import org.prebid.server.hooks.execution.v1.InvocationResultImpl; -import io.vertx.core.Future; public class WURFLDeviceDetectionEntrypointHook implements EntrypointHook { diff --git a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionModule.java b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionModule.java index f929a33ce70..90af5d57138 100644 --- a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionModule.java +++ b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionModule.java @@ -1,8 +1,8 @@ package org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1; -import org.prebid.server.hooks.v1.Module; import org.prebid.server.hooks.v1.Hook; import org.prebid.server.hooks.v1.InvocationContext; +import org.prebid.server.hooks.v1.Module; import java.util.Collection; import java.util.List; diff --git a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionRawAuctionRequestHook.java b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionRawAuctionRequestHook.java index 5a92e051f0c..0a41d67240f 100644 --- a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionRawAuctionRequestHook.java +++ b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionRawAuctionRequestHook.java @@ -1,26 +1,26 @@ package org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1; -import com.iab.openrtb.request.Device; -import org.prebid.server.proto.openrtb.ext.request.ExtDevice; import com.iab.openrtb.request.BidRequest; -import org.prebid.server.log.Logger; -import org.prebid.server.log.LoggerFactory; -import org.prebid.server.json.JacksonMapper; +import com.iab.openrtb.request.Device; +import io.vertx.core.Future; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.prebid.server.auction.model.AuctionContext; +import org.prebid.server.hooks.execution.v1.InvocationResultImpl; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.config.WURFLDeviceDetectionConfigProperties; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.model.AuctionRequestHeadersContext; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.resolver.HeadersResolver; import org.prebid.server.hooks.v1.InvocationAction; import org.prebid.server.hooks.v1.InvocationResult; -import org.prebid.server.hooks.execution.v1.InvocationResultImpl; import org.prebid.server.hooks.v1.InvocationStatus; import org.prebid.server.hooks.v1.auction.AuctionInvocationContext; import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; import org.prebid.server.hooks.v1.auction.RawAuctionRequestHook; -import org.prebid.server.auction.model.AuctionContext; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.log.Logger; +import org.prebid.server.log.LoggerFactory; +import org.prebid.server.proto.openrtb.ext.request.ExtDevice; import org.prebid.server.settings.model.Account; -import io.vertx.core.Future; -import org.apache.commons.lang3.StringUtils; import java.util.Map; import java.util.Objects; diff --git a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLService.java b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLService.java index ccfc848399c..16c96a622b1 100644 --- a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLService.java +++ b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLService.java @@ -3,11 +3,11 @@ import com.scientiamobile.wurfl.core.Device; import com.scientiamobile.wurfl.core.WURFLEngine; import io.vertx.core.Future; -import org.prebid.server.log.Logger; -import org.prebid.server.log.LoggerFactory; import org.prebid.server.execution.file.FileProcessor; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.config.WURFLDeviceDetectionConfigProperties; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.model.WURFLEngineUtils; +import org.prebid.server.log.Logger; +import org.prebid.server.log.LoggerFactory; import java.util.Collections; import java.util.Map; diff --git a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/model/WURFLEngineUtilsTest.java b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/model/WURFLEngineUtilsTest.java index a383f875768..f2ac1e6aec9 100644 --- a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/model/WURFLEngineUtilsTest.java +++ b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/model/WURFLEngineUtilsTest.java @@ -6,9 +6,9 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.config.WURFLDeviceDetectionConfigProperties; -import static org.mockito.Mock.Strictness.LENIENT; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mock.Strictness.LENIENT; @ExtendWith(MockitoExtension.class) public class WURFLEngineUtilsTest { @@ -31,7 +31,7 @@ public void extractWURFLFileNameShouldReturnCorrectFileName() { @Test public void extractWURFLFileNameShouldHandleSimpleFileName() { // given - final String url = "http://example.com/wurfl.zip"; + final String url = "https://example.com/wurfl.zip"; // when final String result = WURFLEngineUtils.extractWURFLFileName(url); diff --git a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/OrtbDeviceUpdaterTest.java b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/OrtbDeviceUpdaterTest.java index 43300b0ff92..631ec438b73 100644 --- a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/OrtbDeviceUpdaterTest.java +++ b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/OrtbDeviceUpdaterTest.java @@ -1,18 +1,18 @@ package org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1; import com.fasterxml.jackson.databind.node.TextNode; +import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; import com.scientiamobile.wurfl.core.exc.VirtualCapabilityNotDefinedException; -import org.mockito.Mock; -import org.prebid.server.proto.openrtb.ext.request.ExtDevice; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.prebid.server.json.ObjectMapperProvider; -import org.prebid.server.json.JacksonMapper; import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; -import com.iab.openrtb.request.BidRequest; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.json.ObjectMapperProvider; +import org.prebid.server.proto.openrtb.ext.request.ExtDevice; import java.math.BigDecimal; import java.util.Set; diff --git a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionModuleTest.java b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionModuleTest.java index 99ae360e5ac..7174398bc71 100644 --- a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionModuleTest.java +++ b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionModuleTest.java @@ -5,8 +5,8 @@ import org.prebid.server.hooks.v1.InvocationContext; import java.util.ArrayList; -import java.util.List; import java.util.Collection; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; diff --git a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionRawAuctionRequestHookTest.java b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionRawAuctionRequestHookTest.java index f981f43ccaa..bada5fc7541 100644 --- a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionRawAuctionRequestHookTest.java +++ b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLDeviceDetectionRawAuctionRequestHookTest.java @@ -1,5 +1,6 @@ package org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.v1; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; import com.scientiamobile.wurfl.core.WURFLEngine; @@ -8,13 +9,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.prebid.server.proto.openrtb.ext.request.ExtDevicePrebid; -import org.prebid.server.proto.openrtb.ext.request.ExtDevice; -import org.prebid.server.proto.openrtb.ext.request.ExtDeviceInt; import org.prebid.server.auction.model.AuctionContext; -import org.prebid.server.settings.model.Account; -import org.prebid.server.json.JacksonMapper; -import org.prebid.server.json.ObjectMapperProvider; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.config.WURFLDeviceDetectionConfigProperties; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.model.AuctionRequestHeadersContext; import org.prebid.server.hooks.v1.InvocationAction; @@ -22,20 +17,26 @@ import org.prebid.server.hooks.v1.InvocationStatus; import org.prebid.server.hooks.v1.auction.AuctionInvocationContext; import org.prebid.server.hooks.v1.auction.AuctionRequestPayload; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.json.ObjectMapperProvider; import org.prebid.server.model.CaseInsensitiveMultiMap; -import com.fasterxml.jackson.databind.node.ObjectNode; +import org.prebid.server.proto.openrtb.ext.request.ExtDevice; +import org.prebid.server.proto.openrtb.ext.request.ExtDeviceInt; +import org.prebid.server.proto.openrtb.ext.request.ExtDevicePrebid; +import org.prebid.server.settings.model.Account; import java.util.Collections; -import java.util.Map; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; @ExtendWith(MockitoExtension.class) public class WURFLDeviceDetectionRawAuctionRequestHookTest { + private final JacksonMapper mapper = new JacksonMapper(ObjectMapperProvider.mapper()); + @Mock private WURFLEngine wurflEngine; @@ -56,8 +57,6 @@ public class WURFLDeviceDetectionRawAuctionRequestHookTest { @Mock(strictness = Mock.Strictness.LENIENT) private com.scientiamobile.wurfl.core.Device wurflDevice; - private JacksonMapper mapper = new JacksonMapper(ObjectMapperProvider.mapper()); - private WURFLDeviceDetectionRawAuctionRequestHook target; @BeforeEach @@ -161,7 +160,7 @@ public void callShouldReturnActionUpdateWhenDeviceHasJustDeviceType() { final AuctionRequestHeadersContext headersContext = AuctionRequestHeadersContext.from(headers); given(context.moduleContext()).willReturn(headersContext); - given(wurflEngine.getDeviceForRequest(any(Map.class))).willReturn(wurflDevice); + given(wurflEngine.getDeviceForRequest(any())).willReturn(wurflDevice); given(wurflDevice.getId()).willReturn("test_phone_ver1"); // when @@ -173,7 +172,7 @@ public void callShouldReturnActionUpdateWhenDeviceHasJustDeviceType() { } @Test - public void callShouldUpdateDeviceWhenWurflDeviceIsDetected() throws Exception { + public void callShouldUpdateDeviceWhenWurflDeviceIsDetected() { // given final String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_2) Version/17.4.1 Mobile/15E148 Safari/604.1"; final Device device = Device.builder().ua(ua).build(); @@ -186,7 +185,7 @@ public void callShouldUpdateDeviceWhenWurflDeviceIsDetected() throws Exception { final AuctionRequestHeadersContext headersContext = AuctionRequestHeadersContext.from(headers); given(context.moduleContext()).willReturn(headersContext); - given(wurflEngine.getDeviceForRequest(any(Map.class))).willReturn(wurflDevice); + given(wurflEngine.getDeviceForRequest(any())).willReturn(wurflDevice); given(wurflDevice.getId()).willReturn("apple_iphone_ver1"); given(wurflDevice.getCapability("brand_name")).willReturn("Apple"); given(wurflDevice.getCapability("model_name")).willReturn("iPhone"); @@ -200,7 +199,7 @@ public void callShouldUpdateDeviceWhenWurflDeviceIsDetected() throws Exception { } @Test - public void shouldEnrichDeviceWhenAllowedPublisherIdsIsEmpty() throws Exception { + public void shouldEnrichDeviceWhenAllowedPublisherIdsIsEmpty() { // given final String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_2) Version/17.4.1 Mobile/15E148 Safari/604.1"; final Device device = Device.builder().ua(ua).build(); @@ -213,7 +212,7 @@ public void shouldEnrichDeviceWhenAllowedPublisherIdsIsEmpty() throws Exception final AuctionRequestHeadersContext headersContext = AuctionRequestHeadersContext.from(headers); given(context.moduleContext()).willReturn(headersContext); - given(wurflEngine.getDeviceForRequest(any(Map.class))).willReturn(wurflDevice); + given(wurflEngine.getDeviceForRequest(any())).willReturn(wurflDevice); given(wurflDevice.getId()).willReturn("apple_iphone_ver1"); given(wurflDevice.getCapability("brand_name")).willReturn("Apple"); given(wurflDevice.getCapability("model_name")).willReturn("iPhone"); @@ -231,7 +230,7 @@ public void shouldEnrichDeviceWhenAllowedPublisherIdsIsEmpty() throws Exception } @Test - public void shouldEnrichDeviceWhenAccountIsAllowed() throws Exception { + public void shouldEnrichDeviceWhenAccountIsAllowed() { // given final String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_2) Version/17.4.1 Mobile/15E148 Safari/604.1"; final Device device = Device.builder().ua(ua).build(); @@ -244,7 +243,7 @@ public void shouldEnrichDeviceWhenAccountIsAllowed() throws Exception { final AuctionRequestHeadersContext headersContext = AuctionRequestHeadersContext.from(headers); given(context.moduleContext()).willReturn(headersContext); - given(wurflEngine.getDeviceForRequest(any(Map.class))).willReturn(wurflDevice); + given(wurflEngine.getDeviceForRequest(any())).willReturn(wurflDevice); given(wurflDevice.getId()).willReturn("apple_iphone_ver1"); given(wurflDevice.getCapability("brand_name")).willReturn("Apple"); given(wurflDevice.getCapability("model_name")).willReturn("iPhone"); diff --git a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLServiceTest.java b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLServiceTest.java index 4dd2cfde2fe..9e8d224a8c5 100644 --- a/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLServiceTest.java +++ b/extra/modules/wurfl-devicedetection/src/test/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/v1/WURFLServiceTest.java @@ -17,12 +17,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; +import static org.mockito.Mock.Strictness.LENIENT; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mock.Strictness.LENIENT; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) public class WURFLServiceTest { @@ -41,10 +41,10 @@ public void setUp() { } @Test - public void setDataPathShouldReturnSucceededFutureWhenProcessingSucceeds() throws Exception { + public void setDataPathShouldReturnSucceededFutureWhenProcessingSucceeds() { // given final String dataFilePath = "test-data-path"; - final String wurflSnapshotUrl = "http://example.com/wurfl-snapshot.zip"; + final String wurflSnapshotUrl = "https://example.com/wurfl-snapshot.zip"; final String wurflFileDirPath = System.getProperty("java.io.tmpdir"); given(configProperties.getFileSnapshotUrl()).willReturn(wurflSnapshotUrl); diff --git a/extra/pom.xml b/extra/pom.xml index 4d058c0ed82..e49c8a219f4 100644 --- a/extra/pom.xml +++ b/extra/pom.xml @@ -4,7 +4,7 @@ org.prebid prebid-server-aggregator - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT pom diff --git a/pom.xml b/pom.xml index 8b908fe1fea..c8fcd3e2b8b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.prebid prebid-server-aggregator - 4.1.0-SNAPSHOT + 4.3.0-SNAPSHOT extra/pom.xml diff --git a/sample/configs/prebid-config-with-optable.yaml b/sample/configs/prebid-config-with-optable.yaml index 77514babf26..93ebd387348 100644 --- a/sample/configs/prebid-config-with-optable.yaml +++ b/sample/configs/prebid-config-with-optable.yaml @@ -13,9 +13,21 @@ adapters: improvedigital: enabled: true colossus: - enabled: true + enabled: true triplelift: enabled: true + adf: + enabled: true + yieldmo: + enabled: true + grid: + enabled: true + unruly: + enabled: true + epsilon: + enabled: true + thirtythreeacross: + enabled: true metrics: prefix: prebid cache: @@ -52,4 +64,4 @@ hooks: enabled: true modules: optable-targeting: - api-endpoint: https://ca.edge.optable.co/v2/targeting?t={TENANT}&o={ORIGIN} + api-endpoint: https://na.edge.optable.co/v2/targeting?t={TENANT}&o={ORIGIN} diff --git a/sample/configs/sample-app-settings-optable.yaml b/sample/configs/sample-app-settings-optable.yaml index 4413a05769d..58238287f58 100644 --- a/sample/configs/sample-app-settings-optable.yaml +++ b/sample/configs/sample-app-settings-optable.yaml @@ -30,6 +30,7 @@ accounts: enrich-web: true enrich-app: true id-prefix-order: "e,v,c" + hid-prefixes: "a,c,i6" ppid-mapping: { "pubcid.org": "c" } adserver-targeting: true cache: diff --git a/src/main/java/com/iab/openrtb/request/Audio.java b/src/main/java/com/iab/openrtb/request/Audio.java index 58901a625b3..3f1fccce76b 100644 --- a/src/main/java/com/iab/openrtb/request/Audio.java +++ b/src/main/java/com/iab/openrtb/request/Audio.java @@ -81,7 +81,7 @@ public class Audio { * within a bid request share the same podid, this indicates that * those impression opportunities belong to the same audio ad pod. */ - Integer podid; + String podid; /** * The sequence (position) of the audio ad pod within a diff --git a/src/main/java/com/iab/openrtb/request/Content.java b/src/main/java/com/iab/openrtb/request/Content.java index 486630d8eed..aae5c19964c 100644 --- a/src/main/java/com/iab/openrtb/request/Content.java +++ b/src/main/java/com/iab/openrtb/request/Content.java @@ -64,6 +64,16 @@ public class Content { */ String genre; + /** + * Taxonomy used by genres. If omitted, Content Category Taxonomy 3.1 (9) is assumed. + */ + Integer gtax; + + /** + * Genre IDs from the taxonomy specified by gtax. + */ + List genres; + /** * Album to which the content belongs; typically for audio. */ @@ -136,7 +146,7 @@ public class Content { List kwarray; /** - * 0 = not live, 1 = content is live (e.g., stream, live blog). + * Indicates whether the broadcast is scheduled: 0 = on-demand, 1 = scheduled (linear viewing). */ Integer livestream; @@ -182,6 +192,16 @@ public class Content { */ Channel channel; + /** + * Indicates whether the event is happening in real time: 0 = replay, 1 = real time. + */ + Integer realtime; + + /** + * Indicates whether this is the first broadcast of the content: 0 = no, 1 = yes. + */ + Integer firstbroadcast; + /** * Placeholder for exchange-specific extensions to OpenRTB. */ diff --git a/src/main/java/com/iab/openrtb/request/Data.java b/src/main/java/com/iab/openrtb/request/Data.java index fd48b7100b8..49a1ee7b7a7 100644 --- a/src/main/java/com/iab/openrtb/request/Data.java +++ b/src/main/java/com/iab/openrtb/request/Data.java @@ -28,6 +28,11 @@ public class Data { */ String name; + /** + * Extended video or audio content IDs from the source specified by name. + */ + List cids; + /** * Array of {@link Segment} (Section 3.2.22) objects that contain the actual data * values. diff --git a/src/main/java/com/iab/openrtb/request/Request.java b/src/main/java/com/iab/openrtb/request/Request.java index 09ddac68d34..f789f64e68e 100644 --- a/src/main/java/com/iab/openrtb/request/Request.java +++ b/src/main/java/com/iab/openrtb/request/Request.java @@ -20,43 +20,67 @@ @Value public class Request { - /** Version in use. **/ + /** + * Version in use. + **/ String ver; - /** The context in which the ad appears. */ + /** + * The context in which the ad appears. + */ Integer context; - /** A more detailed context in which the ad appears. */ + /** + * A more detailed context in which the ad appears. + */ Integer contextsubtype; - /** The design/format/layout of the ad unit being offered. */ + /** + * The design/format/layout of the ad unit being offered. + */ Integer plcmttype; - /** The number of identical placements in this layout */ + /** + * The number of identical placements in this layout + */ Integer plcmtcnt; - /** 0 for the first ad, 1 for the second ad, and so on */ + /** + * 0 for the first ad, 1 for the second ad, and so on + */ Integer seq; - /** Any bid response must comply with the array of elements expressed in the bid request.*/ + /** + * Any bid response must comply with the array of elements expressed in the bid request. + */ List assets; - /** Set to '0' in case if supply source / impression supports returning an assets url. */ + /** + * Set to '0' in case if supply source / impression supports returning an assets url. + */ Integer aurlsupport; - /** Set to '0' in case if supply source / impression supports returning a dco url. */ + /** + * Set to '0' in case if supply source / impression supports returning a dco url. + */ Integer durlsupport; - /** Specifies types of events supported by tracking. */ + /** + * Specifies types of events supported by tracking. + */ List eventtrackers; - /** Set to '0' or field absent if doesn't support custom privacy or support unknown, otherwise '1'. */ + /** + * Set to '0' or field absent if doesn't support custom privacy or support unknown, otherwise '1'. + */ Integer privacy; Integer adunit; Integer layout; - /** Placeholder that may contain custom JSON. */ + /** + * Placeholder that may contain custom JSON. + */ ObjectNode ext; } diff --git a/src/main/java/com/iab/openrtb/request/Segment.java b/src/main/java/com/iab/openrtb/request/Segment.java index 3c765bee874..9239c04f56e 100644 --- a/src/main/java/com/iab/openrtb/request/Segment.java +++ b/src/main/java/com/iab/openrtb/request/Segment.java @@ -15,15 +15,23 @@ @Value public class Segment { - /** ID of the data segment specific to the data provider. */ + /** + * ID of the data segment specific to the data provider. + */ String id; - /** Name of the data segment specific to the data provider. */ + /** + * Name of the data segment specific to the data provider. + */ String name; - /** String representation of the data segment value. */ + /** + * String representation of the data segment value. + */ String value; - /** Placeholder for exchange-specific extensions to OpenRTB. */ + /** + * Placeholder for exchange-specific extensions to OpenRTB. + */ ObjectNode ext; } diff --git a/src/main/java/com/iab/openrtb/request/Video.java b/src/main/java/com/iab/openrtb/request/Video.java index 369d576a3ac..e2c40bb2f31 100644 --- a/src/main/java/com/iab/openrtb/request/Video.java +++ b/src/main/java/com/iab/openrtb/request/Video.java @@ -90,7 +90,7 @@ public class Video { * within a bid request share the same podid, this indicates that * those impression opportunities belong to the same video ad pod. */ - Integer podid; + String podid; /** * The sequence (position) of the video ad pod within a diff --git a/src/main/java/org/prebid/server/Application.java b/src/main/java/org/prebid/server/Application.java index 2490d95a89b..e0cb388433c 100644 --- a/src/main/java/org/prebid/server/Application.java +++ b/src/main/java/org/prebid/server/Application.java @@ -7,7 +7,7 @@ @SpringBootApplication public class Application { - public static void main(String[] args) { + static void main(String[] args) { SpringApplication.run(Application.class, args); } } diff --git a/src/main/java/org/prebid/server/activity/infrastructure/ActivityInfrastructure.java b/src/main/java/org/prebid/server/activity/infrastructure/ActivityInfrastructure.java index 007bf469d1a..d6e37f6cea7 100644 --- a/src/main/java/org/prebid/server/activity/infrastructure/ActivityInfrastructure.java +++ b/src/main/java/org/prebid/server/activity/infrastructure/ActivityInfrastructure.java @@ -1,4 +1,3 @@ - package org.prebid.server.activity.infrastructure; import org.prebid.server.activity.Activity; diff --git a/src/main/java/org/prebid/server/activity/infrastructure/creator/privacy/uscustomlogic/USCustomLogicModuleCreator.java b/src/main/java/org/prebid/server/activity/infrastructure/creator/privacy/uscustomlogic/USCustomLogicModuleCreator.java index 357eb916b5a..ffe20bcdab3 100644 --- a/src/main/java/org/prebid/server/activity/infrastructure/creator/privacy/uscustomlogic/USCustomLogicModuleCreator.java +++ b/src/main/java/org/prebid/server/activity/infrastructure/creator/privacy/uscustomlogic/USCustomLogicModuleCreator.java @@ -81,10 +81,10 @@ public PrivacyModule from(PrivacyModuleCreationContext creationContext) { final List innerPrivacyModules = jsonLogicConfig != null ? SetUtils.emptyIfNull(scope.getSectionsIds()).stream() - .filter(sectionId -> shouldApplyPrivacy(sectionId, moduleConfig)) - .map(sectionId -> forConfig(sectionId, normalizeSection, scope.getGppModel(), jsonLogicConfig)) - .filter(Objects::nonNull) - .toList() + .filter(sectionId -> shouldApplyPrivacy(sectionId, moduleConfig)) + .map(sectionId -> forConfig(sectionId, normalizeSection, scope.getGppModel(), jsonLogicConfig)) + .filter(Objects::nonNull) + .toList() : Collections.emptyList(); return new AndPrivacyModules(innerPrivacyModules); diff --git a/src/main/java/org/prebid/server/activity/infrastructure/creator/rule/ConditionsRuleCreator.java b/src/main/java/org/prebid/server/activity/infrastructure/creator/rule/ConditionsRuleCreator.java index 593fbc69b2c..e068d4a1af6 100644 --- a/src/main/java/org/prebid/server/activity/infrastructure/creator/rule/ConditionsRuleCreator.java +++ b/src/main/java/org/prebid/server/activity/infrastructure/creator/rule/ConditionsRuleCreator.java @@ -69,9 +69,9 @@ private static boolean intersects(Collection configurationSids, Collect private static List geoCodes(List stringGeoCodes) { return stringGeoCodes != null ? stringGeoCodes.stream() - .map(ConditionsRuleCreator::from) - .filter(Objects::nonNull) - .toList() + .map(ConditionsRuleCreator::from) + .filter(Objects::nonNull) + .toList() : null; } diff --git a/src/main/java/org/prebid/server/activity/infrastructure/privacy/uscustomlogic/reader/USColoradoGppReader.java b/src/main/java/org/prebid/server/activity/infrastructure/privacy/uscustomlogic/reader/USColoradoGppReader.java index ee45b9b59b4..a93730e52ae 100644 --- a/src/main/java/org/prebid/server/activity/infrastructure/privacy/uscustomlogic/reader/USColoradoGppReader.java +++ b/src/main/java/org/prebid/server/activity/infrastructure/privacy/uscustomlogic/reader/USColoradoGppReader.java @@ -1,4 +1,3 @@ - package org.prebid.server.activity.infrastructure.privacy.uscustomlogic.reader; import com.iab.gpp.encoder.GppModel; diff --git a/src/main/java/org/prebid/server/activity/infrastructure/rule/ConditionsRule.java b/src/main/java/org/prebid/server/activity/infrastructure/rule/ConditionsRule.java index 3bd4c21045d..913d21a8725 100644 --- a/src/main/java/org/prebid/server/activity/infrastructure/rule/ConditionsRule.java +++ b/src/main/java/org/prebid/server/activity/infrastructure/rule/ConditionsRule.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Value; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.activity.ComponentType; import org.prebid.server.activity.infrastructure.debug.Loggable; import org.prebid.server.activity.infrastructure.payload.ActivityInvocationPayload; @@ -56,8 +56,8 @@ private boolean matchesOneOfGeoCodes(ActivityInvocationPayload activityInvocatio private static boolean matchesGeoCode(GeoCode geoCode, GeoActivityInvocationPayload geoPayload) { final String region = geoCode.getRegion(); - return StringUtils.equalsIgnoreCase(geoCode.getCountry(), geoPayload.country()) - && (region == null || StringUtils.equalsIgnoreCase(region, geoPayload.region())); + return Strings.CI.equals(geoCode.getCountry(), geoPayload.country()) + && (region == null || Strings.CI.equals(region, geoPayload.region())); } private boolean matchesGpc(ActivityInvocationPayload activityInvocationPayload) { diff --git a/src/main/java/org/prebid/server/analytics/reporter/AnalyticsReporterDelegator.java b/src/main/java/org/prebid/server/analytics/reporter/AnalyticsReporterDelegator.java index 28e14a22deb..436ad249263 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/AnalyticsReporterDelegator.java +++ b/src/main/java/org/prebid/server/analytics/reporter/AnalyticsReporterDelegator.java @@ -277,8 +277,8 @@ private AuctionContext updateAuctionContextAdapter(AuctionContext context, Strin return updatedBidRequest != null ? context.toBuilder() - .bidRequest(updatedBidRequest) - .build() + .bidRequest(updatedBidRequest) + .build() : null; } @@ -305,10 +305,10 @@ private BidRequest updateBidRequest(BidRequest bidRequest, return resolvedUser != null || resolvedDevice != null || updatedExtRequest != null ? bidRequest.toBuilder() - .user(resolvedUser != null ? resolvedUser : user) - .device(resolvedDevice != null ? resolvedDevice : device) - .ext(updatedExtRequest != null ? updatedExtRequest : requestExt) - .build() + .user(resolvedUser != null ? resolvedUser : user) + .device(resolvedDevice != null ? resolvedDevice : device) + .ext(updatedExtRequest != null ? updatedExtRequest : requestExt) + .build() : null; } @@ -377,12 +377,12 @@ private Future processFail(Throwable exception, T event, String report private void updateMetricsByEventType(T event, String analyticsCode, MetricName result) { final MetricName eventType = switch (event) { - case AmpEvent ampEvent -> MetricName.event_amp; - case AuctionEvent auctionEvent -> MetricName.event_auction; - case CookieSyncEvent cookieSyncEvent -> MetricName.event_cookie_sync; - case NotificationEvent notificationEvent -> MetricName.event_notification; - case SetuidEvent setuidEvent -> MetricName.event_setuid; - case VideoEvent videoEvent -> MetricName.event_video; + case AmpEvent _ -> MetricName.event_amp; + case AuctionEvent _ -> MetricName.event_auction; + case CookieSyncEvent _ -> MetricName.event_cookie_sync; + case NotificationEvent _ -> MetricName.event_notification; + case SetuidEvent _ -> MetricName.event_setuid; + case VideoEvent _ -> MetricName.event_video; case null, default -> MetricName.event_unknown; }; diff --git a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java index c37ac7aeff2..cb031a0bf7c 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/greenbids/GreenbidsAnalyticsReporter.java @@ -245,7 +245,7 @@ private Map parseAnalyticsResult(Result result) { .collect(Collectors.toMap( Map.Entry::getKey, entry -> parseOrtb2ImpExtResult(entry.getValue()), - (existing, replacement) -> existing)); + (existing, _) -> existing)); } private Ortb2ImpExtResult parseOrtb2ImpExtResult(JsonNode node) { @@ -329,9 +329,13 @@ private CommonMessage createBidMessage( final Map seatsWithNonBids = getSeatsWithNonBids(auctionContext); - final List adUnitsWithBidResponses = imps.stream().map(imp -> - createAdUnit( - imp, seatsWithBids, seatsWithNonBids, bidResponse.getCur(), analyticsResultFromAnalyticsTag)) + final List adUnitsWithBidResponses = imps.stream() + .map(imp -> createAdUnit( + imp, + seatsWithBids, + seatsWithNonBids, + bidResponse.getCur(), + analyticsResultFromAnalyticsTag)) .toList(); final String auctionId = bidRequest @@ -346,17 +350,17 @@ private CommonMessage createBidMessage( final String pbuid = Optional.ofNullable(greenbidsConfig.getPbuid()).orElse(StringUtils.EMPTY); return CommonMessage.builder() - .version(greenbidsAnalyticsProperties.getAnalyticsServerVersion()) - .auctionId(auctionId) - .referrer(referrer) - .sampling(samplingRate) - .prebidServer(prebidVersionProvider.getNameVersionRecord()) - .greenbidsId(greenbidsId) - .pbuid(pbuid) - .billingId(billingId) - .adUnits(adUnitsWithBidResponses) - .auctionElapsed(auctionElapsed) - .build(); + .version(greenbidsAnalyticsProperties.getAnalyticsServerVersion()) + .auctionId(auctionId) + .referrer(referrer) + .sampling(samplingRate) + .prebidServer(prebidVersionProvider.getNameVersionRecord()) + .greenbidsId(greenbidsId) + .pbuid(pbuid) + .billingId(billingId) + .adUnits(adUnitsWithBidResponses) + .auctionElapsed(auctionElapsed) + .build(); } private static Map getSeatsWithBids(BidResponse bidResponse) { @@ -461,14 +465,14 @@ private List extractBidders( final ObjectNode bidders = impExtPrebid.getBidder(); return Stream.concat( - seatsWithBids.entrySet().stream() - .filter(entry -> entry.getValue().getImpid().equals(impId)) - .map(entry -> GreenbidsBid.ofBid( - entry.getKey(), entry.getValue(), bidders.get(entry.getKey()), currency)), - seatsWithNonBids.entrySet().stream() - .filter(entry -> entry.getValue().getImpId().equals(impId)) - .map(entry -> GreenbidsBid.ofNonBid( - entry.getKey(), entry.getValue(), bidders.get(entry.getKey()), currency))) + seatsWithBids.entrySet().stream() + .filter(entry -> entry.getValue().getImpid().equals(impId)) + .map(entry -> GreenbidsBid.ofBid( + entry.getKey(), entry.getValue(), bidders.get(entry.getKey()), currency)), + seatsWithNonBids.entrySet().stream() + .filter(entry -> entry.getValue().getImpId().equals(impId)) + .map(entry -> GreenbidsBid.ofNonBid( + entry.getKey(), entry.getValue(), bidders.get(entry.getKey()), currency))) .toList(); } diff --git a/src/main/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporter.java index fc7a91c11ee..d1239bf160b 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporter.java @@ -88,12 +88,12 @@ private static String buildEventEndpointUrl(String endpoint, EventType eventType @Override public Future processEvent(T event) { final EventType eventType = switch (event) { - case AmpEvent ampEvent -> EventType.amp; - case AuctionEvent auctionEvent -> EventType.auction; - case CookieSyncEvent cookieSyncEvent -> EventType.cookiesync; - case NotificationEvent notificationEvent -> EventType.notification; - case SetuidEvent setuidEvent -> EventType.setuid; - case VideoEvent videoEvent -> EventType.video; + case AmpEvent _ -> EventType.amp; + case AuctionEvent _ -> EventType.auction; + case CookieSyncEvent _ -> EventType.cookiesync; + case NotificationEvent _ -> EventType.notification; + case SetuidEvent _ -> EventType.setuid; + case VideoEvent _ -> EventType.video; case null, default -> null; }; diff --git a/src/main/java/org/prebid/server/auction/AdjustmentFactorResolver.java b/src/main/java/org/prebid/server/auction/AdjustmentFactorResolver.java index 236e4c4c69f..5e593f126dc 100644 --- a/src/main/java/org/prebid/server/auction/AdjustmentFactorResolver.java +++ b/src/main/java/org/prebid/server/auction/AdjustmentFactorResolver.java @@ -1,7 +1,7 @@ package org.prebid.server.auction; import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.proto.openrtb.ext.request.ExtRequestBidAdjustmentFactors; import org.prebid.server.proto.openrtb.ext.request.ImpMediaType; @@ -48,10 +48,10 @@ public BigDecimal resolve(Set impMediaTypes, .map(adjustmentFactorsByMediaTypes::get) .map(bidderToFactor -> MapUtils.isNotEmpty(bidderToFactor) ? bidderToFactor.entrySet().stream() - .filter(entry -> StringUtils.equalsIgnoreCase(entry.getKey(), bidder)) - .map(Map.Entry::getValue) - .findFirst() - .orElse(null) + .filter(entry -> Strings.CI.equals(entry.getKey(), bidder)) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null) : effectiveBidderAdjustmentFactor) .filter(Objects::nonNull) .min(Comparator.comparing(Function.identity())) diff --git a/src/main/java/org/prebid/server/auction/AnalyticsTagsEnricher.java b/src/main/java/org/prebid/server/auction/AnalyticsTagsEnricher.java index 15344b28576..2c985079db0 100644 --- a/src/main/java/org/prebid/server/auction/AnalyticsTagsEnricher.java +++ b/src/main/java/org/prebid/server/auction/AnalyticsTagsEnricher.java @@ -45,10 +45,6 @@ public static AuctionContext enrichWithAnalyticsTags(AuctionContext context) { final List extAnalyticsTags = HookDebugInfoEnricher.toExtAnalyticsTags(context); - if (extAnalyticsTags == null) { - return context; - } - final BidResponse bidResponse = context.getBidResponse(); final Optional ext = Optional.ofNullable(bidResponse.getExt()); final Optional extPrebid = ext.map(ExtBidResponse::getPrebid); @@ -102,7 +98,7 @@ private static AuctionContext addClientDetailsWarning(AuctionContext context) { final Map> warnings = ext .map(ExtBidResponse::getWarnings) .orElse(Collections.emptyMap()); - final List prebidWarnings = ObjectUtils.defaultIfNull( + final List prebidWarnings = ObjectUtils.getIfNull( warnings.get(BidResponseCreator.DEFAULT_DEBUG_KEY), Collections.emptyList()); diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 68c187d8f74..0177e4efe81 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -22,6 +22,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.apache.commons.lang3.tuple.Pair; import org.prebid.server.auction.categorymapping.CategoryMappingService; import org.prebid.server.auction.externalortb.StoredRequestProcessor; @@ -269,7 +270,7 @@ private Bid updateBid(Bid bid, final String generatedBidId = bidIdGenerator.generateId(); final String enforcedRandomBidId = enforcedBidId(bid); - final String effectiveBidId = ObjectUtils.defaultIfNull(generatedBidId, enforcedRandomBidId); + final String effectiveBidId = ObjectUtils.getIfNull(generatedBidId, enforcedRandomBidId); return bid.toBuilder() .id(enforcedRandomBidId) @@ -1529,7 +1530,7 @@ private static boolean eventsEnabledForChannel(AuctionContext auctionContext) { final String channelFromRequest = channelFromRequest(auctionContext.getBidRequest()); return channelConfig.entrySet().stream() - .filter(entry -> StringUtils.equalsIgnoreCase(channelFromRequest, entry.getKey())) + .filter(entry -> Strings.CI.equals(channelFromRequest, entry.getKey())) .findFirst() .map(entry -> BooleanUtils.isTrue(entry.getValue())) .orElse(Boolean.FALSE); @@ -1545,7 +1546,7 @@ private static String channelFromRequest(BidRequest bidRequest) { // TODO: remove alias resolving after transition period private static String recogniseChannelName(String channelName) { - if (StringUtils.equalsIgnoreCase("pbjs", channelName)) { + if (Strings.CI.equals("pbjs", channelName)) { return Ortb2ImplicitParametersResolver.WEB_CHANNEL; } diff --git a/src/main/java/org/prebid/server/auction/CpmRange.java b/src/main/java/org/prebid/server/auction/CpmRange.java index 0310f956025..45dd9bc0bbe 100644 --- a/src/main/java/org/prebid/server/auction/CpmRange.java +++ b/src/main/java/org/prebid/server/auction/CpmRange.java @@ -3,8 +3,8 @@ import org.apache.commons.lang3.ObjectUtils; import org.prebid.server.proto.openrtb.ext.request.ExtGranularityRange; import org.prebid.server.settings.model.Account; -import org.prebid.server.settings.model.AccountAuctionConfig; import org.prebid.server.settings.model.AccountAuctionBidRoundingMode; +import org.prebid.server.settings.model.AccountAuctionConfig; import java.math.BigDecimal; import java.math.RoundingMode; @@ -38,7 +38,7 @@ public static String fromCpm(BigDecimal cpm, PriceGranularity priceGranularity, * Formats {@link BigDecimal} value with a given precision and return its string representation. */ public static String format(BigDecimal value, Integer precision) { - return numberFormat(ObjectUtils.defaultIfNull(precision, DEFAULT_PRECISION)).format(value); + return numberFormat(ObjectUtils.getIfNull(precision, DEFAULT_PRECISION)).format(value); } private static NumberFormat numberFormat(int precision) { diff --git a/src/main/java/org/prebid/server/auction/DebugResolver.java b/src/main/java/org/prebid/server/auction/DebugResolver.java index cbc35ef743a..00a31f69274 100644 --- a/src/main/java/org/prebid/server/auction/DebugResolver.java +++ b/src/main/java/org/prebid/server/auction/DebugResolver.java @@ -3,6 +3,7 @@ import com.iab.openrtb.request.BidRequest; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.debug.DebugContext; import org.prebid.server.bidder.BidderCatalog; @@ -55,7 +56,7 @@ private boolean isDebugEnabled(AuctionContext auctionContext) { private boolean isDebugOverridden(HttpRequestContext httpRequest) { return StringUtils.isNotEmpty(debugOverrideToken) - && StringUtils.equals(httpRequest.getHeaders().get(DEBUG_OVERRIDE_HEADER), debugOverrideToken); + && Strings.CS.equals(httpRequest.getHeaders().get(DEBUG_OVERRIDE_HEADER), debugOverrideToken); } private boolean isDebugEnabledForRequest(BidRequest bidRequest) { @@ -67,7 +68,7 @@ private boolean isDebugEnabledForRequest(BidRequest bidRequest) { private boolean isDebugAllowedByAccount(Account account) { final AccountAuctionConfig auctionConfig = ObjectUtil.getIfNotNull(account, Account::getAuction); final Boolean debugAllowed = ObjectUtil.getIfNotNull(auctionConfig, AccountAuctionConfig::getDebugAllow); - return ObjectUtils.defaultIfNull(debugAllowed, DEFAULT_DEBUG_ALLOWED_BY_ACCOUNT); + return ObjectUtils.getIfNull(debugAllowed, DEFAULT_DEBUG_ALLOWED_BY_ACCOUNT); } private static boolean shouldReturnAllBidStatus(BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/auction/DsaEnforcer.java b/src/main/java/org/prebid/server/auction/DsaEnforcer.java index bdff8fadd46..fafe3a2c5c1 100644 --- a/src/main/java/org/prebid/server/auction/DsaEnforcer.java +++ b/src/main/java/org/prebid/server/auction/DsaEnforcer.java @@ -6,10 +6,10 @@ import com.iab.openrtb.response.Bid; import org.apache.commons.collections4.CollectionUtils; import org.prebid.server.auction.model.AuctionParticipation; +import org.prebid.server.auction.model.BidRejection; import org.prebid.server.auction.model.BidRejectionReason; import org.prebid.server.auction.model.BidRejectionTracker; import org.prebid.server.auction.model.BidderResponse; -import org.prebid.server.auction.model.BidRejection; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderError; import org.prebid.server.bidder.model.BidderSeatBid; diff --git a/src/main/java/org/prebid/server/auction/EidPermissionResolver.java b/src/main/java/org/prebid/server/auction/EidPermissionResolver.java index 6a19fd7c82b..da2ccf1738c 100644 --- a/src/main/java/org/prebid/server/auction/EidPermissionResolver.java +++ b/src/main/java/org/prebid/server/auction/EidPermissionResolver.java @@ -2,7 +2,7 @@ import com.iab.openrtb.request.Eid; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidDataEidPermissions; import java.util.ArrayList; @@ -75,7 +75,7 @@ private boolean isRuleMatched(Eid eid, ExtRequestPrebidDataEidPermissions eidPer private boolean isBidderAllowed(String bidder, List ruleBidders) { return ruleBidders == null || ruleBidders.stream() - .anyMatch(allowedBidder -> StringUtils.equalsIgnoreCase(allowedBidder, bidder) + .anyMatch(allowedBidder -> Strings.CI.equals(allowedBidder, bidder) || WILDCARD_BIDDER.equals(allowedBidder)); } } diff --git a/src/main/java/org/prebid/server/auction/ExchangeService.java b/src/main/java/org/prebid/server/auction/ExchangeService.java index c7258a8faa7..9860ae553df 100644 --- a/src/main/java/org/prebid/server/auction/ExchangeService.java +++ b/src/main/java/org/prebid/server/auction/ExchangeService.java @@ -22,6 +22,7 @@ import org.apache.commons.collections4.map.CaseInsensitiveMap; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.apache.commons.lang3.tuple.Pair; import org.prebid.server.activity.Activity; import org.prebid.server.activity.ComponentType; @@ -294,7 +295,7 @@ private BidderAliases aliases(BidRequest bidRequest, Account account) { ? prebid.getAlternateBidderCodes() : null; - final AlternateBidderCodesConfig alternateBidderCodesConfig = ObjectUtils.defaultIfNull( + final AlternateBidderCodesConfig alternateBidderCodesConfig = ObjectUtils.getIfNull( alternateBidderCodes, account.getAlternateBidderCodes()); @@ -322,16 +323,16 @@ private static BidRequestCacheInfo bidRequestCacheInfo(BidRequest bidRequest, Ac final boolean shouldCacheVideoBids = cache.getVastxml() != null; final boolean shouldCacheWinningBidsOnly = !targeting.getIncludebidderkeys() // ext.prebid.targeting.includebidderkeys takes precedence - && ObjectUtils.defaultIfNull(cache.getWinningonly(), false); + && ObjectUtils.getIfNull(cache.getWinningonly(), false); if (shouldCacheBids || shouldCacheVideoBids || shouldCacheWinningBidsOnly) { final Integer cacheBidsTtl = shouldCacheBids ? cache.getBids().getTtlseconds() : null; final Integer cacheVideoBidsTtl = shouldCacheVideoBids ? cache.getVastxml().getTtlseconds() : null; final boolean returnCreativeBid = shouldCacheBids - ? ObjectUtils.defaultIfNull(cache.getBids().getReturnCreative(), true) + ? ObjectUtils.getIfNull(cache.getBids().getReturnCreative(), true) : false; final boolean returnCreativeVideoBid = shouldCacheVideoBids - ? ObjectUtils.defaultIfNull(cache.getVastxml().getReturnCreative(), true) + ? ObjectUtils.getIfNull(cache.getVastxml().getReturnCreative(), true) : false; return BidRequestCacheInfo.builder() @@ -593,10 +594,10 @@ private Map> prepareUsersAndDevices( final Map> bidderToUserAndDevice = new HashMap<>(); for (String bidder : bidders) { - final ExtBidderConfigOrtb fpdConfig = ObjectUtils.defaultIfNull(biddersToConfigs.get(bidder), + final ExtBidderConfigOrtb fpdConfig = ObjectUtils.getIfNull(biddersToConfigs.get(bidder), biddersToConfigs.get(ALL_BIDDERS_CONFIG)); final boolean useFirstPartyData = firstPartyDataBidders == null || firstPartyDataBidders.stream() - .anyMatch(fpdBidder -> StringUtils.equalsIgnoreCase(fpdBidder, bidder)); + .anyMatch(fpdBidder -> Strings.CI.equals(fpdBidder, bidder)); final User preparedUser = prepareUser( bidder, context, aliases, useFirstPartyData, fpdConfig, eidPermissionResolver); final Device preparedDevice = prepareDevice( @@ -791,9 +792,9 @@ private BidRequest prepareBidRequest(BidderPrivacyResult bidderPrivacyResult, final boolean transmitTid = transmitTransactionId(bidder, context); final List firstPartyDataBidders = firstPartyDataBidders(bidRequest.getExt()); final boolean useFirstPartyData = firstPartyDataBidders == null || firstPartyDataBidders.stream() - .anyMatch(fpdBidder -> StringUtils.equalsIgnoreCase(fpdBidder, bidder)); + .anyMatch(fpdBidder -> Strings.CI.equals(fpdBidder, bidder)); - final ExtBidderConfigOrtb fpdConfig = ObjectUtils.defaultIfNull( + final ExtBidderConfigOrtb fpdConfig = ObjectUtils.getIfNull( biddersToConfigs.get(bidder), biddersToConfigs.get(ALL_BIDDERS_CONFIG)); @@ -953,9 +954,9 @@ private App prepareApp(App app, ObjectNode fpdApp, boolean useFirstPartyData) { final App maskedApp = shouldCleanExtData || shouldCleanContentData ? app.toBuilder() - .ext(shouldCleanExtData ? maskExtApp(appExt) : appExt) - .content(shouldCleanContentData ? prepareContent(content) : content) - .build() + .ext(shouldCleanExtData ? maskExtApp(appExt) : appExt) + .content(shouldCleanContentData ? prepareContent(content) : content) + .build() : app; return useFirstPartyData ? fpdResolver.resolveApp(maskedApp, fpdApp) : maskedApp; @@ -981,9 +982,9 @@ private Site prepareSite(Site site, ObjectNode fpdSite, boolean useFirstPartyDat final Site maskedSite = shouldCleanExtData || shouldCleanContentData ? site.toBuilder() - .ext(shouldCleanExtData ? maskExtSite(siteExt) : siteExt) - .content(shouldCleanContentData ? prepareContent(content) : content) - .build() + .ext(shouldCleanExtData ? maskExtSite(siteExt) : siteExt) + .content(shouldCleanContentData ? prepareContent(content) : content) + .build() : site; return useFirstPartyData ? fpdResolver.resolveSite(maskedSite, fpdSite) : maskedSite; @@ -1002,9 +1003,9 @@ private Dooh prepareDooh(Dooh dooh, ObjectNode fpdDooh, boolean useFirstPartyDat final Dooh maskedDooh = shouldCleanExtData || shouldCleanContentData ? dooh.toBuilder() - .ext(shouldCleanExtData ? null : doohExt) - .content(shouldCleanContentData ? prepareContent(content) : content) - .build() + .ext(shouldCleanExtData ? null : doohExt) + .content(shouldCleanContentData ? prepareContent(content) : content) + .build() : dooh; return useFirstPartyData ? fpdResolver.resolveDooh(maskedDooh, fpdDooh) : maskedDooh; @@ -1027,9 +1028,9 @@ private Source prepareSource(String bidder, BidRequest bidRequest, boolean trans return receivedSource == null ? Source.builder().schain(bidderSchain).build() : receivedSource.toBuilder() - .schain(bidderSchain != null ? bidderSchain : receivedSource.getSchain()) - .tid(transmitTid ? receivedSource.getTid() : null) - .build(); + .schain(bidderSchain != null ? bidderSchain : receivedSource.getSchain()) + .tid(transmitTid ? receivedSource.getTid() : null) + .build(); } private ExtRequest prepareExt(String bidder, @@ -1133,7 +1134,7 @@ private Future> processAndRequestBids(AuctionContext // and only merge this copy back if secondary bidder has completed in time final Map copiedBidRejectionTrackers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - for (Map.Entry entry: auctionContext.getBidRejectionTrackers().entrySet()) { + for (Map.Entry entry : auctionContext.getBidRejectionTrackers().entrySet()) { copiedBidRejectionTrackers.put(entry.getKey(), BidRejectionTracker.copyOf(entry.getValue())); } @@ -1155,7 +1156,7 @@ private Future> processAndRequestBids(AuctionContext return Future.succeededFuture(bidderToFutureResponse.entrySet().stream() .filter(entry -> !entry.getValue().failed()) - .map(MapUtil.mapEntryValueMapper((bidder, futureResponse) -> ObjectUtils.defaultIfNull( + .map(MapUtil.mapEntryValueMapper((bidder, futureResponse) -> ObjectUtils.getIfNull( futureResponse.result(), responseForUncompletedSecondaryBidder(bidder)))) .map(MapUtil.mapEntryMapper((bidder, bidderResponse) -> bidderToAuctionParticipation.get(bidder).with(bidderResponse))) @@ -1273,7 +1274,7 @@ private Timeout adjustTimeout(Timeout timeout, long startTime, long currentTime) private BidderSeatBid populateBidderCode(BidderSeatBid seatBid, String bidderName, String resolvedBidderName) { return seatBid.with(seatBid.getBids().stream() .map(bidderBid -> bidderBid.toBuilder() - .seat(ObjectUtils.defaultIfNull(bidderBid.getSeat(), bidderName)) + .seat(ObjectUtils.getIfNull(bidderBid.getSeat(), bidderName)) .bid(bidderBid.getBid().toBuilder() .ext(prepareBidExt( bidderBid.getBid().getExt(), @@ -1316,8 +1317,8 @@ private BidderResponse rejectBidderResponseOrProceed(HookStageExecutionResult warnings) { return CollectionUtils.isNotEmpty(warnings) ? seatBid.toBuilder() - .warnings(ListUtil.union(warnings, seatBid.getWarnings())) - .build() + .warnings(ListUtil.union(warnings, seatBid.getWarnings())) + .build() : seatBid; } @@ -1464,6 +1465,7 @@ private List updateResponsesMetrics(List updateResponsesMetrics(List updateResponsesMetrics(List fieldNames = node.fieldNames(); while (fieldNames.hasNext()) { final String fieldName = fieldNames.next(); - if (StringUtils.equalsIgnoreCase(fieldName, bidderName)) { + if (Strings.CI.equals(fieldName, bidderName)) { return node.get(fieldName); } } diff --git a/src/main/java/org/prebid/server/auction/ImplicitParametersExtractor.java b/src/main/java/org/prebid/server/auction/ImplicitParametersExtractor.java index eae090780c5..b0b639f87d0 100644 --- a/src/main/java/org/prebid/server/auction/ImplicitParametersExtractor.java +++ b/src/main/java/org/prebid/server/auction/ImplicitParametersExtractor.java @@ -3,6 +3,7 @@ import de.malkusch.whoisServerList.publicSuffixList.PublicSuffixList; import io.vertx.core.MultiMap; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.exception.PreBidException; import org.prebid.server.model.CaseInsensitiveMultiMap; import org.prebid.server.model.HttpRequestContext; @@ -34,7 +35,7 @@ public String refererFrom(HttpRequestContext request) { final String url = StringUtils.isNotBlank(urlOverride) ? urlOverride : StringUtils.trimToNull(request.getHeaders().get(HttpUtil.REFERER_HEADER)); - return StringUtils.isNotBlank(url) && !StringUtils.startsWith(url, "http") + return StringUtils.isNotBlank(url) && !Strings.CS.startsWith(url, "http") ? "http://" + url : url; } @@ -98,8 +99,8 @@ public String uaFrom(HttpRequestContext request) { * scheme is 'https'. Returns 1 if one of these conditions evaluates to true or null otherwise. */ public Integer secureFrom(HttpRequestContext httpRequest) { - return StringUtils.equalsIgnoreCase(httpRequest.getHeaders().get("X-Forwarded-Proto"), "https") - || StringUtils.equalsIgnoreCase(httpRequest.getScheme(), "https") + return Strings.CI.equals(httpRequest.getHeaders().get("X-Forwarded-Proto"), "https") + || Strings.CI.equals(httpRequest.getScheme(), "https") ? 1 : null; } diff --git a/src/main/java/org/prebid/server/auction/SupplyChainResolver.java b/src/main/java/org/prebid/server/auction/SupplyChainResolver.java index 6c7246ced6f..6acd448ec29 100644 --- a/src/main/java/org/prebid/server/auction/SupplyChainResolver.java +++ b/src/main/java/org/prebid/server/auction/SupplyChainResolver.java @@ -7,6 +7,7 @@ import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; import org.prebid.server.log.Logger; @@ -48,7 +49,7 @@ public SupplyChain resolveForBidder(String bidder, BidRequest bidRequest) { bidderSchain = existingSchainOrNull(bidder, bidderSchain, schain); } - return enrich(ObjectUtils.defaultIfNull(bidderSchain, catchAllSchain), bidRequest); + return enrich(ObjectUtils.getIfNull(bidderSchain, catchAllSchain), bidRequest); } private static SupplyChainNode globalNodeOrNull(String globalNodeString, JacksonMapper mapper) { @@ -84,7 +85,7 @@ private static boolean containsBidder(ExtRequestPrebidSchain schainEntry, String .map(ExtRequestPrebidSchain::getBidders) .filter(Objects::nonNull) .flatMap(Collection::stream) - .anyMatch(schainEntryBidder -> StringUtils.equalsIgnoreCase(schainEntryBidder, bidder)); + .anyMatch(schainEntryBidder -> Strings.CI.equals(schainEntryBidder, bidder)); } private SupplyChain enrich(SupplyChain bidderSpecificSchain, BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/auction/TargetingKeywordsResolver.java b/src/main/java/org/prebid/server/auction/TargetingKeywordsResolver.java index c5527ce0a74..fa4d0993853 100644 --- a/src/main/java/org/prebid/server/auction/TargetingKeywordsResolver.java +++ b/src/main/java/org/prebid/server/auction/TargetingKeywordsResolver.java @@ -5,6 +5,7 @@ import com.iab.openrtb.response.Bid; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.request.ExtRequest; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; @@ -60,7 +61,7 @@ private Map> rulesBySource() final List rules = get(get(extRequest, ExtRequest::getPrebid), ExtRequestPrebid::getAdservertargeting); - return ObjectUtils.>defaultIfNull(rules, Collections.emptyList()) + return ObjectUtils.>getIfNull(rules, Collections.emptyList()) .stream() .filter(TargetingKeywordsResolver::isValid) .collect(Collectors.groupingBy(ExtRequestPrebidAdservertargetingRule::getSource)); @@ -160,7 +161,7 @@ private Map resolveResponseKeywords(Bid bid, String bidder) { mapper.mapper().valueToTree(bid), responseRules, value -> StringUtils.substringAfter(value, SEATBID_BID_PREFIX), - key -> StringUtils.replace(key, BIDDER_MACRO, bidder)); + key -> Strings.CS.replace(key, BIDDER_MACRO, bidder)); } return Collections.emptyMap(); diff --git a/src/main/java/org/prebid/server/auction/UidUpdater.java b/src/main/java/org/prebid/server/auction/UidUpdater.java index 014c0d93898..94f1745d617 100644 --- a/src/main/java/org/prebid/server/auction/UidUpdater.java +++ b/src/main/java/org/prebid/server/auction/UidUpdater.java @@ -3,6 +3,7 @@ import com.iab.openrtb.request.User; import org.apache.commons.collections4.map.CaseInsensitiveMap; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.aliases.BidderAliases; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.bidder.BidderCatalog; @@ -75,7 +76,7 @@ private String uidFromUidsCookie(UidsCookie uidsCookie, String bidder) { private String uidFromHostCookie(AuctionContext auctionContext, String bidder) { return bidderCatalog.cookieFamilyName(bidder) - .filter(cookieFamily -> StringUtils.equals(cookieFamily, hostCookieFamily)) + .filter(cookieFamily -> Strings.CS.equals(cookieFamily, hostCookieFamily)) .map(cookieFamily -> uidsCookieService.parseHostCookie(auctionContext.getHttpRequest())) .orElse(null); } diff --git a/src/main/java/org/prebid/server/auction/aliases/BidderAliases.java b/src/main/java/org/prebid/server/auction/aliases/BidderAliases.java index aade755a9ec..10b2644d8a9 100644 --- a/src/main/java/org/prebid/server/auction/aliases/BidderAliases.java +++ b/src/main/java/org/prebid/server/auction/aliases/BidderAliases.java @@ -4,7 +4,7 @@ import org.apache.commons.collections4.map.CaseInsensitiveMap; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.BidderCatalog; import java.util.Collection; @@ -72,7 +72,7 @@ public String resolveBidder(String aliasOrBidder) { } public boolean isSame(String bidder1, String bidder2) { - return StringUtils.equalsIgnoreCase(resolveBidder(bidder1), resolveBidder(bidder2)); + return Strings.CI.equals(resolveBidder(bidder1), resolveBidder(bidder2)); } public Integer resolveAliasVendorId(String alias) { diff --git a/src/main/java/org/prebid/server/auction/bidderrequestpostprocessor/BidderRequestCleaner.java b/src/main/java/org/prebid/server/auction/bidderrequestpostprocessor/BidderRequestCleaner.java index 6b311f878d1..763ef39e6ae 100644 --- a/src/main/java/org/prebid/server/auction/bidderrequestpostprocessor/BidderRequestCleaner.java +++ b/src/main/java/org/prebid/server/auction/bidderrequestpostprocessor/BidderRequestCleaner.java @@ -5,7 +5,7 @@ import com.iab.openrtb.request.BidRequest; import io.vertx.core.Future; import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.aliases.BidderAliases; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.BidderRequest; @@ -124,7 +124,7 @@ private static Map cleanBidderMap(Map map, String bidd } for (Map.Entry entry : map.entrySet()) { - if (StringUtils.equalsIgnoreCase(entry.getKey(), bidder)) { + if (Strings.CI.equals(entry.getKey(), bidder)) { return Collections.singletonMap(entry.getKey(), entry.getValue()); } } @@ -165,7 +165,7 @@ private static UpdateResult cleanBidAdjustments(ObjectNode bidAdjust } for (Iterator bidders = bidderMap.fieldNames(); bidders.hasNext(); ) { - if (!StringUtils.equalsIgnoreCase(bidders.next(), bidder)) { + if (!Strings.CI.equals(bidders.next(), bidder)) { bidders.remove(); } } diff --git a/src/main/java/org/prebid/server/auction/bidderrequestpostprocessor/BidderRequestPreferredMediaProcessor.java b/src/main/java/org/prebid/server/auction/bidderrequestpostprocessor/BidderRequestPreferredMediaProcessor.java index fb685298a4a..3104875c0dd 100644 --- a/src/main/java/org/prebid/server/auction/bidderrequestpostprocessor/BidderRequestPreferredMediaProcessor.java +++ b/src/main/java/org/prebid/server/auction/bidderrequestpostprocessor/BidderRequestPreferredMediaProcessor.java @@ -9,7 +9,7 @@ import com.iab.openrtb.request.Video; import io.vertx.core.Future; import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.aliases.BidderAliases; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.BidRejectionReason; @@ -97,7 +97,7 @@ private static Optional preferredMediaType(Account account, String bi private static Optional getBidder(String bidderName, JsonNode biddersNode) { return StreamUtil.asStream(biddersNode.fieldNames()) - .filter(fieldName -> StringUtils.equalsIgnoreCase(bidderName, fieldName)) + .filter(fieldName -> Strings.CI.equals(bidderName, fieldName)) .map(biddersNode::get) .findAny(); } diff --git a/src/main/java/org/prebid/server/auction/externalortb/StoredResponseProcessor.java b/src/main/java/org/prebid/server/auction/externalortb/StoredResponseProcessor.java index 09f4a39b587..c0dc8c92a5f 100644 --- a/src/main/java/org/prebid/server/auction/externalortb/StoredResponseProcessor.java +++ b/src/main/java/org/prebid/server/auction/externalortb/StoredResponseProcessor.java @@ -11,6 +11,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.map.CaseInsensitiveMap; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.model.AuctionParticipation; import org.prebid.server.auction.model.BidRejectionTracker; import org.prebid.server.auction.model.BidderRequest; @@ -336,7 +337,7 @@ private static BidderSeatBid updateSeatBid(BidderSeatBid bidderSeatBid, String i private static BidderBid resolveBidImpId(BidderBid bidderBid, String impId) { final Bid bid = bidderBid.getBid(); final String bidImpId = bid.getImpid(); - if (!StringUtils.contains(bidImpId, PBS_IMPID_MACRO)) { + if (!Strings.CS.contains(bidImpId, PBS_IMPID_MACRO)) { return bidderBid; } @@ -421,15 +422,15 @@ private BidderSeatBid makeBidderSeatBid(BidderSeatBid bidderSeatBid, final boolean nonNullBidderSeatBid = bidderSeatBid != null; final String bidCurrency = nonNullBidderSeatBid ? bidderSeatBid.getBids().stream() - .map(BidderBid::getBidCurrency) - .filter(Objects::nonNull) - .findAny() - .orElse(DEFAULT_BID_CURRENCY) + .map(BidderBid::getBidCurrency) + .filter(Objects::nonNull) + .findAny() + .orElse(DEFAULT_BID_CURRENCY) : DEFAULT_BID_CURRENCY; final List bidderBids = seatBid != null ? seatBid.getBid().stream() - .map(bid -> makeBidderBid(bid, bidCurrency, seatBid.getSeat(), impIdToBidType)) - .collect(Collectors.toCollection(ArrayList::new)) + .map(bid -> makeBidderBid(bid, bidCurrency, seatBid.getSeat(), impIdToBidType)) + .collect(Collectors.toCollection(ArrayList::new)) : new ArrayList<>(); if (nonNullBidderSeatBid) { bidderBids.addAll(bidderSeatBid.getBids()); diff --git a/src/main/java/org/prebid/server/auction/gpp/AmpGppService.java b/src/main/java/org/prebid/server/auction/gpp/AmpGppService.java index ea3823a961a..229ffa7827a 100644 --- a/src/main/java/org/prebid/server/auction/gpp/AmpGppService.java +++ b/src/main/java/org/prebid/server/auction/gpp/AmpGppService.java @@ -65,9 +65,9 @@ public BidRequest updateBidRequest(BidRequest bidRequest, AuctionContext auction return updatedUser.isUpdated() || updatedRegs.isUpdated() ? bidRequest.toBuilder() - .user(updatedUser.getValue()) - .regs(updatedRegs.getValue()) - .build() + .user(updatedUser.getValue()) + .regs(updatedRegs.getValue()) + .build() : bidRequest; } diff --git a/src/main/java/org/prebid/server/auction/gpp/AuctionGppService.java b/src/main/java/org/prebid/server/auction/gpp/AuctionGppService.java index b6b823c4903..9a5624ca652 100644 --- a/src/main/java/org/prebid/server/auction/gpp/AuctionGppService.java +++ b/src/main/java/org/prebid/server/auction/gpp/AuctionGppService.java @@ -99,9 +99,9 @@ public BidRequest updateBidRequest(BidRequest bidRequest, AuctionContext auction return updatedUser.isUpdated() || updatedRegs.isUpdated() ? bidRequest.toBuilder() - .user(updatedUser.getValue()) - .regs(updatedRegs.getValue()) - .build() + .user(updatedUser.getValue()) + .regs(updatedRegs.getValue()) + .build() : bidRequest; } @@ -112,10 +112,10 @@ private static UpdateResult updateUser(User user, GppContext gppContext) { ? UpdateResult.updated( Optional.ofNullable(user) - .map(User::toBuilder) - .orElseGet(User::builder) - .consent(updatedConsent.getValue()) - .build()) + .map(User::toBuilder) + .orElseGet(User::builder) + .consent(updatedConsent.getValue()) + .build()) : UpdateResult.unaltered(user); } @@ -141,11 +141,11 @@ private static UpdateResult updateRegs(Regs regs, GppContext gppContext) { ? UpdateResult.updated( Optional.ofNullable(regs) - .map(Regs::toBuilder) - .orElseGet(Regs::builder) - .gdpr(updatedGdpr.getValue()) - .usPrivacy(updatedUsPrivacy.getValue()) - .build()) + .map(Regs::toBuilder) + .orElseGet(Regs::builder) + .gdpr(updatedGdpr.getValue()) + .usPrivacy(updatedUsPrivacy.getValue()) + .build()) : UpdateResult.unaltered(regs); } diff --git a/src/main/java/org/prebid/server/auction/gpp/CookieSyncGppService.java b/src/main/java/org/prebid/server/auction/gpp/CookieSyncGppService.java index 2ebe39a8cb8..a786b170ba3 100644 --- a/src/main/java/org/prebid/server/auction/gpp/CookieSyncGppService.java +++ b/src/main/java/org/prebid/server/auction/gpp/CookieSyncGppService.java @@ -72,10 +72,10 @@ public CookieSyncRequest updateCookieSyncRequest(CookieSyncRequest cookieSyncReq return updatedGdpr.isUpdated() || updatedConsent.isUpdated() || updatedUsPrivacy.isUpdated() ? cookieSyncRequest.toBuilder() - .gdpr(updatedGdpr.getValue()) - .gdprConsent(updatedConsent.getValue()) - .usPrivacy(updatedUsPrivacy.getValue()) - .build() + .gdpr(updatedGdpr.getValue()) + .gdprConsent(updatedConsent.getValue()) + .usPrivacy(updatedUsPrivacy.getValue()) + .build() : cookieSyncRequest; } diff --git a/src/main/java/org/prebid/server/auction/gpp/SetuidGppService.java b/src/main/java/org/prebid/server/auction/gpp/SetuidGppService.java index f923711447b..9c271ccb771 100644 --- a/src/main/java/org/prebid/server/auction/gpp/SetuidGppService.java +++ b/src/main/java/org/prebid/server/auction/gpp/SetuidGppService.java @@ -68,14 +68,14 @@ public SetuidContext updateSetuidContext(SetuidContext setuidContext) { return updatedGdpr.isUpdated() || updatedConsent.isUpdated() ? setuidContext.toBuilder() - .privacyContext(PrivacyContext.of( - privacy.toBuilder() - .gdpr(updatedGdpr.getValue().toString()) - .consentString(updatedConsent.getValue()) - .build(), - privacyContext.getTcfContext(), - privacyContext.getIpAddress())) - .build() + .privacyContext(PrivacyContext.of( + privacy.toBuilder() + .gdpr(updatedGdpr.getValue().toString()) + .consentString(updatedConsent.getValue()) + .build(), + privacyContext.getTcfContext(), + privacyContext.getIpAddress())) + .build() : setuidContext; } diff --git a/src/main/java/org/prebid/server/auction/privacy/contextfactory/AmpPrivacyContextFactory.java b/src/main/java/org/prebid/server/auction/privacy/contextfactory/AmpPrivacyContextFactory.java index 84f9695c3ea..8a8f24685e4 100644 --- a/src/main/java/org/prebid/server/auction/privacy/contextfactory/AmpPrivacyContextFactory.java +++ b/src/main/java/org/prebid/server/auction/privacy/contextfactory/AmpPrivacyContextFactory.java @@ -121,8 +121,8 @@ private static AccountGdprConfig accountGdprConfig(Account account) { private static RequestLogInfo requestLogInfo(MetricName requestType, BidRequest bidRequest, String accountId) { final String referrerUrl = MetricName.openrtb2web == requestType ? Optional.ofNullable(bidRequest.getSite()) - .map(Site::getRef) - .orElse(null) + .map(Site::getRef) + .orElse(null) : null; return RequestLogInfo.of(requestType, referrerUrl, accountId); diff --git a/src/main/java/org/prebid/server/auction/privacy/enforcement/PrivacyEnforcementService.java b/src/main/java/org/prebid/server/auction/privacy/enforcement/PrivacyEnforcementService.java index b14ff44444c..544346901ee 100644 --- a/src/main/java/org/prebid/server/auction/privacy/enforcement/PrivacyEnforcementService.java +++ b/src/main/java/org/prebid/server/auction/privacy/enforcement/PrivacyEnforcementService.java @@ -3,10 +3,10 @@ import com.iab.openrtb.request.Device; import com.iab.openrtb.request.User; import io.vertx.core.Future; +import org.apache.commons.lang3.tuple.Pair; import org.prebid.server.auction.aliases.BidderAliases; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.BidderPrivacyResult; -import org.apache.commons.lang3.tuple.Pair; import java.util.List; import java.util.Map; diff --git a/src/main/java/org/prebid/server/auction/requestfactory/AmpRequestFactory.java b/src/main/java/org/prebid/server/auction/requestfactory/AmpRequestFactory.java index 1dd2c18c921..d74b37fa4d6 100644 --- a/src/main/java/org/prebid/server/auction/requestfactory/AmpRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/requestfactory/AmpRequestFactory.java @@ -17,6 +17,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.DebugResolver; import org.prebid.server.auction.FpdResolver; import org.prebid.server.auction.GeoLocationServiceWrapper; @@ -345,9 +346,9 @@ private static String addtlConsentFromQueryStringParams(HttpRequestContext httpR private static Integer gdprFromQueryStringParams(HttpRequestContext httpRequest) { final String gdprAppliesParam = httpRequest.getQueryParams().get(GDPR_APPLIES_PARAM); - if (StringUtils.equals(gdprAppliesParam, "true")) { + if (Strings.CS.equals(gdprAppliesParam, "true")) { return 1; - } else if (StringUtils.equals(gdprAppliesParam, "false")) { + } else if (Strings.CS.equals(gdprAppliesParam, "false")) { return 0; } diff --git a/src/main/java/org/prebid/server/auction/requestfactory/AuctionRequestFactory.java b/src/main/java/org/prebid/server/auction/requestfactory/AuctionRequestFactory.java index d043d6e6a4d..fb2d89beb07 100644 --- a/src/main/java/org/prebid/server/auction/requestfactory/AuctionRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/requestfactory/AuctionRequestFactory.java @@ -200,8 +200,8 @@ private BidRequest jsonNodeAsBidRequest(JsonNode bidRequestNode) { private BidRequest fillWithValuesFromHttpRequest(BidRequest bidRequest, HttpRequestContext httpRequest) { return !containsRegsExtGpc(bidRequest) ? bidRequest.toBuilder() - .regs(fillRegsWithValuesFromHttpRequest(bidRequest.getRegs(), httpRequest)) - .build() + .regs(fillRegsWithValuesFromHttpRequest(bidRequest.getRegs(), httpRequest)) + .build() : bidRequest; } diff --git a/src/main/java/org/prebid/server/auction/requestfactory/Ortb2ImplicitParametersResolver.java b/src/main/java/org/prebid/server/auction/requestfactory/Ortb2ImplicitParametersResolver.java index a26b1a0433b..cdcc68485cc 100644 --- a/src/main/java/org/prebid/server/auction/requestfactory/Ortb2ImplicitParametersResolver.java +++ b/src/main/java/org/prebid/server/auction/requestfactory/Ortb2ImplicitParametersResolver.java @@ -24,6 +24,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.ImplicitParametersExtractor; import org.prebid.server.auction.IpAddressHelper; import org.prebid.server.auction.PriceGranularity; @@ -191,7 +192,7 @@ public BidRequest resolve(BidRequest bidRequest, final ExtRequest populatedExt = populateRequestExt( ext, bidRequest, - ObjectUtils.defaultIfNull(populatedImps, imps), + ObjectUtils.getIfNull(populatedImps, imps), auctionContext.getHttpRequest().getHttpMethod().name(), endpoint, auctionContext.getAccount()); @@ -288,7 +289,7 @@ private Device populateDevice(Device device, App app, HttpRequestContext httpReq private Integer resolveDntHeader(HttpRequestContext request) { final String dnt = request.getHeaders().get(HttpUtil.DNT_HEADER.toString()); - return StringUtils.equalsAny(dnt, "0", "1") ? Integer.valueOf(dnt) : null; + return Strings.CS.equalsAny(dnt, "0", "1") ? Integer.valueOf(dnt) : null; } private String sanitizeIp(String ip, IpAddress.IP version) { @@ -318,7 +319,7 @@ private static void logWarnIfNoIp(String resolvedIp, String resolvedIpv6) { } private static Integer resolveLmt(Device device, App app) { - if (app == null || device == null || !StringUtils.equalsIgnoreCase(device.getOs(), "ios")) { + if (app == null || device == null || !Strings.CI.equals(device.getOs(), "ios")) { return null; } @@ -406,12 +407,12 @@ private Site populateSite(Site site, HttpRequestContext httpRequest) { final String domain = site != null ? StringUtils.trimToNull(site.getDomain()) : null; final String updatedDomain = domain == null - ? HttpUtil.getHostFromUrl(ObjectUtils.defaultIfNull(updatedPage, page)) + ? HttpUtil.getHostFromUrl(ObjectUtils.getIfNull(updatedPage, page)) : null; final Publisher publisher = site != null ? site.getPublisher() : null; final Publisher updatedPublisher = populateSitePublisher( - publisher, ObjectUtils.defaultIfNull(updatedDomain, domain)); + publisher, ObjectUtils.getIfNull(updatedDomain, domain)); final ExtSite siteExt = site != null ? site.getExt() : null; final ExtSite updatedSiteExt = siteExt == null || siteExt.getAmp() == null @@ -424,10 +425,10 @@ private Site populateSite(Site site, HttpRequestContext httpRequest) { return (site == null ? Site.builder() : site.toBuilder()) // do not set page if domain was not parsed successfully - .page(domainPresent ? ObjectUtils.defaultIfNull(updatedPage, page) : page) - .domain(ObjectUtils.defaultIfNull(updatedDomain, domain)) - .publisher(ObjectUtils.defaultIfNull(updatedPublisher, publisher)) - .ext(ObjectUtils.defaultIfNull(updatedSiteExt, siteExt)) + .page(domainPresent ? ObjectUtils.getIfNull(updatedPage, page) : page) + .domain(ObjectUtils.getIfNull(updatedDomain, domain)) + .publisher(ObjectUtils.getIfNull(updatedPublisher, publisher)) + .ext(ObjectUtils.getIfNull(updatedSiteExt, siteExt)) .build(); } return null; @@ -486,7 +487,7 @@ private static String populateTidValue(String tid, boolean hasStoredBidRequest, IdGenerator tidGenerator) { - final boolean containsTidMacro = StringUtils.containsIgnoreCase(tid, OVERRIDE_SOURCE_ID_TEMPLATE); + final boolean containsTidMacro = Strings.CI.contains(tid, OVERRIDE_SOURCE_ID_TEMPLATE); if (StringUtils.isNotBlank(tid) && !containsTidMacro && !(generateBidRequestId @@ -501,7 +502,7 @@ private static String populateTidValue(String tid, && hasStoredBidRequest) && !containsTidMacro ? generatedId - : StringUtils.replaceIgnoreCase(tid, OVERRIDE_SOURCE_ID_TEMPLATE, generatedId); + : Strings.CI.replace(tid, OVERRIDE_SOURCE_ID_TEMPLATE, generatedId); } private SupplyChain populateSupplyChain(SupplyChain supplyChain, ExtRequest extRequest) { @@ -738,11 +739,11 @@ private ExtRequest populateRequestExt(ExtRequest ext, : ExtRequestPrebid.builder(); final ExtRequest updatedExt = ExtRequest.of(prebidBuilder - .targeting(ObjectUtils.defaultIfNull(updatedTargeting, + .targeting(ObjectUtils.getIfNull(updatedTargeting, ObjectUtil.getIfNotNull(prebid, ExtRequestPrebid::getTargeting))) - .cache(ObjectUtils.defaultIfNull(updatedCache, + .cache(ObjectUtils.getIfNull(updatedCache, ObjectUtil.getIfNotNull(prebid, ExtRequestPrebid::getCache))) - .channel(ObjectUtils.defaultIfNull(updatedChannel, + .channel(ObjectUtils.getIfNull(updatedChannel, ObjectUtil.getIfNotNull(prebid, ExtRequestPrebid::getChannel))) .server(serverInfo.with(httpMethod, endpoint)) .build()); @@ -829,7 +830,7 @@ private ExtRequestTargeting targetingOrNull(ExtRequestPrebid prebid, List i */ private boolean isWinningOnly(ExtRequestPrebidCache cache) { final Boolean cacheWinningOnly = cache != null ? cache.getWinningonly() : null; - return ObjectUtils.defaultIfNull(cacheWinningOnly, shouldCacheOnlyWinningBids); + return ObjectUtils.getIfNull(cacheWinningOnly, shouldCacheOnlyWinningBids); } /** @@ -925,7 +926,7 @@ private ExtRequestPrebidChannel channelOrNull(ExtRequestPrebid prebid, BidReques } private static ExtRequestPrebidChannel populateChannel(BidRequest bidRequest, String endpoint) { - if (StringUtils.equals(Endpoint.openrtb2_amp.value(), endpoint)) { + if (Strings.CS.equals(Endpoint.openrtb2_amp.value(), endpoint)) { return ExtRequestPrebidChannel.of(AMP_CHANNEL); } else if (bidRequest.getApp() != null) { return ExtRequestPrebidChannel.of(APP_CHANNEL); diff --git a/src/main/java/org/prebid/server/auction/requestfactory/Ortb2RequestFactory.java b/src/main/java/org/prebid/server/auction/requestfactory/Ortb2RequestFactory.java index e7d42855464..1d5ff3b7293 100644 --- a/src/main/java/org/prebid/server/auction/requestfactory/Ortb2RequestFactory.java +++ b/src/main/java/org/prebid/server/auction/requestfactory/Ortb2RequestFactory.java @@ -315,9 +315,9 @@ public Future enrichBidRequestWithAccountAndPrivacyData(AuctionConte } return Future.succeededFuture(bidRequest.toBuilder() - .ext(ObjectUtils.defaultIfNull(enrichedRequestExt, requestExt)) - .device(ObjectUtils.defaultIfNull(enrichedDevice, device)) - .regs(ObjectUtils.defaultIfNull(enrichedRegs, regs)) + .ext(ObjectUtils.getIfNull(enrichedRequestExt, requestExt)) + .device(ObjectUtils.getIfNull(enrichedDevice, device)) + .regs(ObjectUtils.getIfNull(enrichedRegs, regs)) .build()); } @@ -498,12 +498,12 @@ private String accountIdFromBidRequest(BidRequest bidRequest) { final Publisher publisher = ObjectUtils.firstNonNull(appPublisher, doohPublisher, sitePublisher); final String publisherId = publisher != null ? resolvePublisherId(publisher) : null; - return ObjectUtils.defaultIfNull(publisherId, StringUtils.EMPTY); + return ObjectUtils.getIfNull(publisherId, StringUtils.EMPTY); } private String resolvePublisherId(Publisher publisher) { final String parentAccountId = parentAccountIdFromExtPublisher(publisher.getExt()); - return ObjectUtils.defaultIfNull(parentAccountId, publisher.getId()); + return ObjectUtils.getIfNull(parentAccountId, publisher.getId()); } private String parentAccountIdFromExtPublisher(ExtPublisher extPublisher) { @@ -725,8 +725,8 @@ private static UpdateResult resolveRegion(Geo originalGeo, GeoInfo geoIn return upperCasedRegion != null && !upperCasedRegion.equals(upperCasedRegionInRequest) ? UpdateResult.updated(upperCasedRegion) : Objects.equals(regionInRequest, upperCasedRegionInRequest) - ? UpdateResult.unaltered(regionInRequest) - : UpdateResult.updated(upperCasedRegionInRequest); + ? UpdateResult.unaltered(regionInRequest) + : UpdateResult.updated(upperCasedRegionInRequest); } private static CaseInsensitiveMultiMap toCaseInsensitiveMultiMap(MultiMap originalMap) { diff --git a/src/main/java/org/prebid/server/auction/requestfactory/VideoRequestFactory.java b/src/main/java/org/prebid/server/auction/requestfactory/VideoRequestFactory.java index 0c732095e60..4989c920c53 100644 --- a/src/main/java/org/prebid/server/auction/requestfactory/VideoRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/requestfactory/VideoRequestFactory.java @@ -268,9 +268,9 @@ private String accountIdFrom(BidRequestVideo bidRequestVideo) { final Site site = bidRequestVideo.getSite(); final Publisher sitePublisher = site != null ? site.getPublisher() : null; - final Publisher publisher = ObjectUtils.defaultIfNull(appPublisher, sitePublisher); + final Publisher publisher = ObjectUtils.getIfNull(appPublisher, sitePublisher); final String publisherId = publisher != null ? resolvePublisherId(publisher) : null; - return ObjectUtils.defaultIfNull(publisherId, StringUtils.EMPTY); + return ObjectUtils.getIfNull(publisherId, StringUtils.EMPTY); } /** @@ -279,7 +279,7 @@ private String accountIdFrom(BidRequestVideo bidRequestVideo) { */ private String resolvePublisherId(Publisher publisher) { final String parentAccountId = parentAccountIdFromExtPublisher(publisher.getExt()); - return ObjectUtils.defaultIfNull(parentAccountId, publisher.getId()); + return ObjectUtils.getIfNull(parentAccountId, publisher.getId()); } /** diff --git a/src/main/java/org/prebid/server/auction/versionconverter/down/BidRequestOrtb26To25Converter.java b/src/main/java/org/prebid/server/auction/versionconverter/down/BidRequestOrtb26To25Converter.java index 43de9dff9a0..49a2c2f6170 100644 --- a/src/main/java/org/prebid/server/auction/versionconverter/down/BidRequestOrtb26To25Converter.java +++ b/src/main/java/org/prebid/server/auction/versionconverter/down/BidRequestOrtb26To25Converter.java @@ -57,11 +57,11 @@ public BidRequest convert(BidRequest bidRequest) { modifiedRegs) ? bidRequest.toBuilder() - .imp(modifiedImps != null ? modifiedImps : imps) - .user(modifiedUser != null ? modifiedUser : user) - .source(modifiedSource != null ? modifiedSource : source) - .regs(modifiedRegs != null ? modifiedRegs : regs) - .build() + .imp(modifiedImps != null ? modifiedImps : imps) + .user(modifiedUser != null ? modifiedUser : user) + .source(modifiedSource != null ? modifiedSource : source) + .regs(modifiedRegs != null ? modifiedRegs : regs) + .build() : bidRequest; } @@ -76,7 +76,7 @@ private List modifyImps(List imps) { } return IntStream.range(0, imps.size()) - .mapToObj(i -> ObjectUtils.defaultIfNull(modifiedImps.get(i), imps.get(i))) + .mapToObj(i -> ObjectUtils.getIfNull(modifiedImps.get(i), imps.get(i))) .toList(); } diff --git a/src/main/java/org/prebid/server/auction/versionconverter/up/BidRequestOrtb25To26Converter.java b/src/main/java/org/prebid/server/auction/versionconverter/up/BidRequestOrtb25To26Converter.java index 56cdae70eb1..bbc1a96e6a8 100644 --- a/src/main/java/org/prebid/server/auction/versionconverter/up/BidRequestOrtb25To26Converter.java +++ b/src/main/java/org/prebid/server/auction/versionconverter/up/BidRequestOrtb25To26Converter.java @@ -47,11 +47,11 @@ public BidRequest convert(BidRequest bidRequest) { return ObjectUtils.anyNotNull(modifiedImps, modifiedSource, modifiedRegs, modifiedUser) ? bidRequest.toBuilder() - .imp(modifiedImps != null ? modifiedImps : imps) - .source(modifiedSource != null ? modifiedSource : source) - .regs(modifiedRegs != null ? modifiedRegs : regs) - .user(modifiedUser != null ? modifiedUser : user) - .build() + .imp(modifiedImps != null ? modifiedImps : imps) + .source(modifiedSource != null ? modifiedSource : source) + .regs(modifiedRegs != null ? modifiedRegs : regs) + .user(modifiedUser != null ? modifiedUser : user) + .build() : bidRequest; } @@ -65,7 +65,7 @@ private static List moveImpsData(List imps) { } return IntStream.range(0, imps.size()) - .mapToObj(i -> ObjectUtils.defaultIfNull(modifiedImps.get(i), imps.get(i))) + .mapToObj(i -> ObjectUtils.getIfNull(modifiedImps.get(i), imps.get(i))) .toList(); } @@ -86,9 +86,9 @@ private static Imp moveImpData(Imp imp) { return ObjectUtils.anyNotNull(resolvedRewarded, resolvedExtImp) ? imp.toBuilder() - .rwdd(resolvedRewarded != null ? resolvedRewarded : rewarded) - .ext(resolvedExtImp != null ? resolvedExtImp : extImp) - .build() + .rwdd(resolvedRewarded != null ? resolvedRewarded : rewarded) + .ext(resolvedExtImp != null ? resolvedExtImp : extImp) + .build() : null; } @@ -132,9 +132,9 @@ private static Source moveSourceData(Source source) { return ObjectUtils.anyNotNull(resolvedSupplyChain, resolvedExtSource) ? source.toBuilder() - .schain(resolvedSupplyChain != null ? resolvedSupplyChain : supplyChain) - .ext(resolvedExtSource != null ? nullIfEmpty(resolvedExtSource) : extSource) - .build() + .schain(resolvedSupplyChain != null ? resolvedSupplyChain : supplyChain) + .ext(resolvedExtSource != null ? nullIfEmpty(resolvedExtSource) : extSource) + .build() : null; } @@ -179,10 +179,10 @@ private static Regs moveRegsData(Regs regs) { return ObjectUtils.anyNotNull(resolvedGdpr, resolvedUsPrivacy, resolvedExtRegs) ? regs.toBuilder() - .gdpr(resolvedGdpr != null ? resolvedGdpr : gdpr) - .usPrivacy(resolvedUsPrivacy != null ? resolvedUsPrivacy : usPrivacy) - .ext(resolvedExtRegs != null ? nullIfEmpty(resolvedExtRegs) : extRegs) - .build() + .gdpr(resolvedGdpr != null ? resolvedGdpr : gdpr) + .usPrivacy(resolvedUsPrivacy != null ? resolvedUsPrivacy : usPrivacy) + .ext(resolvedExtRegs != null ? nullIfEmpty(resolvedExtRegs) : extRegs) + .build() : null; } @@ -223,10 +223,10 @@ private static User moveUserData(User user) { return ObjectUtils.anyNotNull(resolvedConsent, resolvedEids, resolvedExtUser) ? user.toBuilder() - .consent(resolvedConsent != null ? resolvedConsent : consent) - .eids(resolvedEids != null ? resolvedEids : eids) - .ext(resolvedExtUser != null ? nullIfEmpty(resolvedExtUser) : extUser) - .build() + .consent(resolvedConsent != null ? resolvedConsent : consent) + .eids(resolvedEids != null ? resolvedEids : eids) + .ext(resolvedExtUser != null ? nullIfEmpty(resolvedExtUser) : extUser) + .build() : null; } diff --git a/src/main/java/org/prebid/server/bidadjustments/BidAdjustmentFactorResolver.java b/src/main/java/org/prebid/server/bidadjustments/BidAdjustmentFactorResolver.java index 8218bfd8547..5f8911ba13d 100644 --- a/src/main/java/org/prebid/server/bidadjustments/BidAdjustmentFactorResolver.java +++ b/src/main/java/org/prebid/server/bidadjustments/BidAdjustmentFactorResolver.java @@ -1,7 +1,7 @@ package org.prebid.server.bidadjustments; import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.proto.openrtb.ext.request.ExtRequestBidAdjustmentFactors; import org.prebid.server.proto.openrtb.ext.request.ImpMediaType; @@ -41,7 +41,7 @@ private static Optional resolveFromMediaTypes( .map(type -> type == ImpMediaType.video_instream ? ImpMediaType.video : type) .map(adjustmentFactors::get) .flatMap(factors -> factors.entrySet().stream() - .filter(entry -> StringUtils.equalsIgnoreCase(entry.getKey(), bidderCode)) + .filter(entry -> Strings.CI.equals(entry.getKey(), bidderCode)) .map(Map.Entry::getValue) .findFirst()); } diff --git a/src/main/java/org/prebid/server/bidadjustments/BidAdjustmentsEnricher.java b/src/main/java/org/prebid/server/bidadjustments/BidAdjustmentsEnricher.java index 7ac48388c2e..e15154261f0 100644 --- a/src/main/java/org/prebid/server/bidadjustments/BidAdjustmentsEnricher.java +++ b/src/main/java/org/prebid/server/bidadjustments/BidAdjustmentsEnricher.java @@ -5,13 +5,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import org.prebid.server.auction.model.AuctionContext; +import org.prebid.server.bidadjustments.model.BidAdjustments; import org.prebid.server.json.JacksonMapper; import org.prebid.server.json.JsonMerger; import org.prebid.server.log.ConditionalLogger; import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; import org.prebid.server.proto.openrtb.ext.request.ExtRequest; -import org.prebid.server.bidadjustments.model.BidAdjustments; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; import org.prebid.server.settings.model.Account; import org.prebid.server.settings.model.AccountAuctionConfig; diff --git a/src/main/java/org/prebid/server/bidadjustments/FloorAdjustmentFactorResolver.java b/src/main/java/org/prebid/server/bidadjustments/FloorAdjustmentFactorResolver.java index 86dd863d1c3..efd807564cc 100644 --- a/src/main/java/org/prebid/server/bidadjustments/FloorAdjustmentFactorResolver.java +++ b/src/main/java/org/prebid/server/bidadjustments/FloorAdjustmentFactorResolver.java @@ -1,7 +1,7 @@ package org.prebid.server.bidadjustments; import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.proto.openrtb.ext.request.ExtRequestBidAdjustmentFactors; import org.prebid.server.proto.openrtb.ext.request.ImpMediaType; @@ -36,10 +36,10 @@ public BigDecimal resolve(Set impMediaTypes, .map(adjustmentFactorsByMediaTypes::get) .map(bidderToFactor -> MapUtils.isNotEmpty(bidderToFactor) ? bidderToFactor.entrySet().stream() - .filter(entry -> StringUtils.equalsIgnoreCase(entry.getKey(), bidder)) - .map(Map.Entry::getValue) - .findFirst() - .orElse(null) + .filter(entry -> Strings.CI.equals(entry.getKey(), bidder)) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null) : effectiveBidderAdjustmentFactor) .filter(Objects::nonNull) .min(Comparator.comparing(Function.identity())) diff --git a/src/main/java/org/prebid/server/bidder/BidderInfo.java b/src/main/java/org/prebid/server/bidder/BidderInfo.java index d26cc2c4b2c..58ee88197a7 100644 --- a/src/main/java/org/prebid/server/bidder/BidderInfo.java +++ b/src/main/java/org/prebid/server/bidder/BidderInfo.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Value; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.versionconverter.OrtbVersion; import org.prebid.server.spring.config.bidder.model.CompressionType; import org.prebid.server.spring.config.bidder.model.MediaType; @@ -66,7 +66,7 @@ public static BidderInfo create(boolean enabled, enabled, ortbVersion, debugAllowed, - StringUtils.startsWith(endpoint, "https://"), + Strings.CS.startsWith(endpoint, "https://"), aliasOf, new MaintainerInfo(maintainerEmail), new CapabilitiesInfo( diff --git a/src/main/java/org/prebid/server/bidder/UsersyncInfoFactory.java b/src/main/java/org/prebid/server/bidder/UsersyncInfoFactory.java index cccc0082991..fc0aeb87f3b 100644 --- a/src/main/java/org/prebid/server/bidder/UsersyncInfoFactory.java +++ b/src/main/java/org/prebid/server/bidder/UsersyncInfoFactory.java @@ -62,13 +62,13 @@ private String buildSyncUrl(String bidder, UsersyncMethod usersyncMethod, Privac private String buildSetUidUrl(String bidder, String uid, UsersyncMethod usersyncMethod, Privacy privacy) { return callbackUrlTemplate - .replaceMacros(prepareRedirectParams(bidder, uid, usersyncMethod)) + .replaceMacros(prepareRedirectParams(bidder, usersyncMethod)) .replaceMacros(preparePrivacyParams(privacy)) .expand() + "&uid=" + StringUtils.defaultString(uid); // uid macro should not be url-encoded } - private Map prepareRedirectParams(String bidder, String uid, UsersyncMethod method) { + private Map prepareRedirectParams(String bidder, UsersyncMethod method) { return Map.of( BIDDER_PLACEHOLDER, bidder, FORMAT_PLACEHOLDER, resolveFormat(method).name); diff --git a/src/main/java/org/prebid/server/bidder/adf/AdfBidder.java b/src/main/java/org/prebid/server/bidder/adf/AdfBidder.java index 6d8f89335e4..c1e55bf8332 100644 --- a/src/main/java/org/prebid/server/bidder/adf/AdfBidder.java +++ b/src/main/java/org/prebid/server/bidder/adf/AdfBidder.java @@ -85,7 +85,7 @@ private ExtImpAdf parseImpExt(Imp imp) { } private BidRequest modifyBidRequest(BidRequest bidRequest, List imps, String priceType) { - final ExtRequest extRequest = ObjectUtils.defaultIfNull(bidRequest.getExt(), ExtRequest.empty()); + final ExtRequest extRequest = ObjectUtils.getIfNull(bidRequest.getExt(), ExtRequest.empty()); final ExtRequest modifiedExtRequest = StringUtils.isNotEmpty(priceType) ? modifyExtRequest(extRequest, priceType) : extRequest; diff --git a/src/main/java/org/prebid/server/bidder/admixer/AdmixerBidder.java b/src/main/java/org/prebid/server/bidder/admixer/AdmixerBidder.java index 4ddb522f74f..e5853b8b4a1 100644 --- a/src/main/java/org/prebid/server/bidder/admixer/AdmixerBidder.java +++ b/src/main/java/org/prebid/server/bidder/admixer/AdmixerBidder.java @@ -95,7 +95,7 @@ private static BigDecimal resolveBidFloor(BigDecimal customBidFloor, BigDecimal final BigDecimal resolvedCustomBidFloor = isValidBidFloor(customBidFloor) ? customBidFloor : null; final BigDecimal resolvedBidFloor = isValidBidFloor(bidFloor) ? bidFloor : null; - return ObjectUtils.defaultIfNull(resolvedBidFloor, resolvedCustomBidFloor); + return ObjectUtils.getIfNull(resolvedBidFloor, resolvedCustomBidFloor); } private static boolean isValidBidFloor(BigDecimal bidFloor) { diff --git a/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java b/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java index 9038069a989..f2aff26f826 100644 --- a/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java +++ b/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java @@ -22,6 +22,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusMetaData; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusNativeRequest; @@ -213,7 +214,7 @@ private static AdnuntiusRequestAdUnit.AdnuntiusRequestAdUnitBuilder makeAdUnitBu String bidType) { final String auId = extImpAdnuntius.getAuId(); - final ExtImpAdnuntiusTargeting targeting = ObjectUtils.defaultIfNull( + final ExtImpAdnuntiusTargeting targeting = ObjectUtils.getIfNull( extImpAdnuntius.getTargeting(), ExtImpAdnuntiusTargeting.builder().build()); return AdnuntiusRequestAdUnit.builder() @@ -447,7 +448,7 @@ private static boolean isValid(AdnuntiusAdUnit adsUnit) { } final String targetId = extractTargetId(adsUnit.getTargetId()); - final int matchedCount = ObjectUtils.defaultIfNull(adsUnit.getMatchedAdCount(), 0); + final int matchedCount = ObjectUtils.getIfNull(adsUnit.getMatchedAdCount(), 0); final List ads = adsUnit.getAds(); final BigDecimal bidAmount = CollectionUtils.emptyIfNull(ads).stream() .findFirst() @@ -523,10 +524,10 @@ private static BigDecimal resolvePrice(AdnuntiusAd ad, String bidType) { if (StringUtils.isEmpty(bidType)) { amount = ObjectUtil.getIfNotNull(ad.getBid(), AdnuntiusBid::getAmount); } - if (StringUtils.endsWithIgnoreCase(bidType, "net")) { + if (Strings.CI.endsWith(bidType, "net")) { amount = ObjectUtil.getIfNotNull(ad.getNetBid(), AdnuntiusNetBid::getAmount); } - if (StringUtils.endsWithIgnoreCase(bidType, "gross")) { + if (Strings.CI.endsWith(bidType, "gross")) { amount = ObjectUtil.getIfNotNull(ad.getGrossBid(), AdnuntiusGrossBid::getAmount); } diff --git a/src/main/java/org/prebid/server/bidder/adot/AdotBidder.java b/src/main/java/org/prebid/server/bidder/adot/AdotBidder.java index 4ef80b28de0..b08b67adefe 100644 --- a/src/main/java/org/prebid/server/bidder/adot/AdotBidder.java +++ b/src/main/java/org/prebid/server/bidder/adot/AdotBidder.java @@ -121,8 +121,8 @@ private static Bid resolveMacros(Bid bid) { final String priceAsString = price != null ? price.toPlainString() : "0"; return bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) .build(); } diff --git a/src/main/java/org/prebid/server/bidder/adprime/AdprimeBidder.java b/src/main/java/org/prebid/server/bidder/adprime/AdprimeBidder.java index b1773d3e2d5..32f97c7c51b 100644 --- a/src/main/java/org/prebid/server/bidder/adprime/AdprimeBidder.java +++ b/src/main/java/org/prebid/server/bidder/adprime/AdprimeBidder.java @@ -108,8 +108,8 @@ private Site resolveSite(BidRequest bidRequest, ExtImpAdprime extImpAdprime) { return Objects.nonNull(site) && CollectionUtils.isNotEmpty(keywords) ? site.toBuilder() - .keywords(String.join(",", keywords)) - .build() + .keywords(String.join(",", keywords)) + .build() : site; } diff --git a/src/main/java/org/prebid/server/bidder/adquery/AdQueryBidder.java b/src/main/java/org/prebid/server/bidder/adquery/AdQueryBidder.java index 40416c80db0..203631ec74d 100644 --- a/src/main/java/org/prebid/server/bidder/adquery/AdQueryBidder.java +++ b/src/main/java/org/prebid/server/bidder/adquery/AdQueryBidder.java @@ -132,8 +132,8 @@ private static String getImpSizes(Imp imp) { if (CollectionUtils.isNotEmpty(format)) { return format.stream() .map(singleFormat -> FORMAT_TEMPLATE.formatted( - ObjectUtils.defaultIfNull(singleFormat.getW(), 0), - ObjectUtils.defaultIfNull(singleFormat.getH(), 0))) + ObjectUtils.getIfNull(singleFormat.getW(), 0), + ObjectUtils.getIfNull(singleFormat.getH(), 0))) .collect(Collectors.joining(",")); } @@ -159,7 +159,7 @@ private static MultiMap makeHeaders(Device device) { } @Override - public final Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { final AdQueryResponse bidResponse = mapper.decodeValue( httpCall.getResponse().getBody(), AdQueryResponse.class); diff --git a/src/main/java/org/prebid/server/bidder/adswag/AdswagBidder.java b/src/main/java/org/prebid/server/bidder/adswag/AdswagBidder.java new file mode 100644 index 00000000000..065e946d335 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/adswag/AdswagBidder.java @@ -0,0 +1,331 @@ +package org.prebid.server.bidder.adswag; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.App; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Format; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.Publisher; +import com.iab.openrtb.request.Site; +import com.iab.openrtb.request.Video; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.prebid.server.bidder.Bidder; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.json.DecodeException; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.adswag.ExtImpAdswag; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.BidderUtil; +import org.prebid.server.util.HttpUtil; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Pattern; + +public class AdswagBidder implements Bidder { + + private static final TypeReference> TYPE_REFERENCE = new TypeReference<>() { + }; + + private static final String DEFAULT_CURRENCY = "EUR"; + private static final Pattern VAST_MARKUP = Pattern.compile("<\\s*VAST[\\s/>]", Pattern.CASE_INSENSITIVE); + + private final String endpointUrl; + private final JacksonMapper mapper; + + public AdswagBidder(String endpointUrl, JacksonMapper mapper) { + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public Result>> makeHttpRequests(BidRequest request) { + final Map> impsByPublisher = new LinkedHashMap<>(); + final List errors = new ArrayList<>(); + + for (Imp imp : request.getImp()) { + final ExtImpAdswag extImpAdswag; + try { + extImpAdswag = parseImpExt(imp); + validateImpExt(extImpAdswag, imp.getId()); + } catch (PreBidException e) { + errors.add(BidderError.badInput(e.getMessage())); + continue; + } + + impsByPublisher + .computeIfAbsent(extImpAdswag.getPublisherId(), _ -> new ArrayList<>()) + .add(modifyImp(imp, extImpAdswag.getPlacementId())); + } + + if (impsByPublisher.isEmpty()) { + return Result.withErrors(errors); + } + + if (request.getSite() == null && request.getApp() == null) { + errors.add(BidderError.badInput("request must contain either site or app")); + return Result.withErrors(errors); + } + + final List> httpRequests = impsByPublisher.entrySet().stream() + .map(group -> modifyBidRequest(request, group.getKey(), group.getValue())) + .map(modifiedRequest -> BidderUtil.defaultRequest(modifiedRequest, endpointUrl, mapper)) + .toList(); + + return Result.of(httpRequests, errors); + } + + private ExtImpAdswag parseImpExt(Imp imp) { + try { + return mapper.mapper().convertValue(imp.getExt(), TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException("Error parsing imp.ext for impression " + imp.getId()); + } + } + + private static void validateImpExt(ExtImpAdswag extImpAdswag, String impId) { + if (StringUtils.isBlank(extImpAdswag.getPublisherId())) { + throw new PreBidException("missing publisherId for imp " + impId); + } + } + + private static Imp modifyImp(Imp imp, String placementId) { + final ObjectNode modifiedExt = imp.getExt().deepCopy(); + modifiedExt.remove("bidder"); + modifiedExt.remove("prebid"); + if (StringUtils.isNotBlank(placementId)) { + modifiedExt.putObject("adswag").put("placement_id", placementId); + } + + return imp.toBuilder().ext(modifiedExt.isEmpty() ? null : modifiedExt).build(); + } + + private static BidRequest modifyBidRequest(BidRequest request, String publisherId, List modifiedImps) { + return request.toBuilder() + .site(modifySite(request.getSite(), publisherId)) + .app(modifyApp(request.getApp(), publisherId)) + .imp(modifiedImps) + .build(); + } + + private static Site modifySite(Site site, String publisherId) { + return site != null + ? site.toBuilder().publisher(modifyPublisher(site.getPublisher(), publisherId)).build() + : null; + } + + private static App modifyApp(App app, String publisherId) { + return app != null + ? app.toBuilder().publisher(modifyPublisher(app.getPublisher(), publisherId)).build() + : null; + } + + private static Publisher modifyPublisher(Publisher publisher, String publisherId) { + return Optional.ofNullable(publisher) + .map(Publisher::toBuilder) + .orElseGet(Publisher::builder) + .id(publisherId) + .build(); + } + + @Override + public final Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + final String body = httpCall.getResponse().getBody(); + if (StringUtils.isBlank(body)) { + return Result.empty(); + } + + try { + final BidResponse bidResponse = mapper.decodeValue(body, BidResponse.class); + final List errors = new ArrayList<>(); + final List bids = extractBids(httpCall.getRequest().getPayload(), bidResponse, errors); + return Result.of(bids, errors); + } catch (DecodeException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + } + + private List extractBids(BidRequest bidRequest, BidResponse bidResponse, List errors) { + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Collections.emptyList(); + } + + final String currency = StringUtils.defaultIfBlank(bidResponse.getCur(), DEFAULT_CURRENCY); + return bidResponse.getSeatbid().stream() + .filter(Objects::nonNull) + .map(SeatBid::getBid) + .filter(Objects::nonNull) + .flatMap(List::stream) + .filter(Objects::nonNull) + .map(bid -> makeBidderBid(bid, bidRequest.getImp(), currency, errors)) + .filter(Objects::nonNull) + .toList(); + } + + private BidderBid makeBidderBid(Bid bid, List imps, String currency, List errors) { + final Imp imp = findImp(imps, bid.getImpid()); + if (imp == null) { + errors.add(BidderError.badServerResponse( + "bid %s references unknown imp %s".formatted(bid.getId(), bid.getImpid()))); + return null; + } + + final String serveUrl = serveUrl(bid); + if (StringUtils.isBlank(bid.getAdm()) && StringUtils.isBlank(serveUrl)) { + errors.add(BidderError.badServerResponse( + "bid %s has neither adm nor ext.adswag.serve_url".formatted(bid.getId()))); + return null; + } + + final BidType bidType; + try { + bidType = resolveBidType(imp, bid); + } catch (PreBidException e) { + errors.add(BidderError.badServerResponse(e.getMessage())); + return null; + } + + final Bid modifiedBid = switch (bidType) { + case banner -> makeBannerBid(bid, serveUrl, imp.getBanner()); + case video -> makeVideoBid(bid, serveUrl, imp.getVideo()); + case audio -> makeAudioBid(bid, serveUrl); + // should never happen + default -> throw new AssertionError(); + }; + + return BidderBid.of(modifiedBid, bidType, currency); + } + + private static Imp findImp(List imps, String impId) { + return imps.stream() + .filter(imp -> Objects.equals(imp.getId(), impId)) + .findFirst() + .orElse(null); + } + + private static String serveUrl(Bid bid) { + final JsonNode serveUrlNode = bid.getExt() != null + ? bid.getExt().path("adswag").path("serve_url") + : null; + return serveUrlNode != null && serveUrlNode.isTextual() ? serveUrlNode.textValue() : null; + } + + private static BidType resolveBidType(Imp imp, Bid bid) { + final Integer mtype = bid.getMtype(); + if (mtype != null) { + return switch (mtype) { + case 1 -> BidType.banner; + case 2 -> BidType.video; + case 3 -> BidType.audio; + default -> throw new PreBidException( + "unsupported bid.mtype %d for impression %s".formatted(mtype, bid.getImpid())); + }; + } + + final boolean isVast = bid.getAdm() != null && VAST_MARKUP.matcher(bid.getAdm()).find(); + if (imp.getAudio() != null && (isVast || imp.getBanner() == null)) { + return BidType.audio; + } + if (imp.getVideo() != null && (isVast || imp.getBanner() == null)) { + return BidType.video; + } + if (imp.getBanner() != null) { + return BidType.banner; + } + throw new PreBidException("unable to resolve media type for impression " + bid.getImpid()); + } + + private static Bid makeBannerBid(Bid bid, String serveUrl, Banner banner) { + final Format size = bannerSize(banner); + final boolean updateSize = hasNoSize(bid) && size != null; + + return bid.toBuilder() + .adm(StringUtils.isBlank(bid.getAdm()) ? iframeMarkup(serveUrl, size) : bid.getAdm()) + .w(updateSize ? size.getW() : bid.getW()) + .h(updateSize ? size.getH() : bid.getH()) + .mtype(1) + .build(); + } + + private static Format bannerSize(Banner banner) { + if (banner == null) { + return null; + } + if (CollectionUtils.isNotEmpty(banner.getFormat())) { + return banner.getFormat().getFirst(); + } + if (banner.getW() != null && banner.getH() != null) { + return Format.builder().w(banner.getW()).h(banner.getH()).build(); + } + return null; + } + + private static String iframeMarkup(String serveUrl, Format size) { + final StringBuilder markup = new StringBuilder() + .append(""""); + + return markup.toString(); + } + + // Mirrors Go's html.EscapeString so both server adapters emit identical markup. + private static String escapeHtmlAttribute(String value) { + return value + .replace("&", "&") + .replace("'", "'") + .replace("<", "<") + .replace(">", ">") + .replace("\"", """); + } + + private static boolean hasNoSize(Bid bid) { + return bid.getW() == null || bid.getW() <= 0 || bid.getH() == null || bid.getH() <= 0; + } + + private static Bid makeVideoBid(Bid bid, String serveUrl, Video video) { + final boolean updateSize = hasNoSize(bid) && video != null && video.getW() != null && video.getH() != null; + return bid.toBuilder() + .nurl(StringUtils.isBlank(bid.getAdm()) ? serveUrl : bid.getNurl()) + .w(updateSize ? video.getW() : bid.getW()) + .h(updateSize ? video.getH() : bid.getH()) + .mtype(2) + .build(); + } + + private static Bid makeAudioBid(Bid bid, String serveUrl) { + return bid.toBuilder() + .nurl(StringUtils.isBlank(bid.getAdm()) ? serveUrl : bid.getNurl()) + .mtype(3) + .build(); + } +} diff --git a/src/main/java/org/prebid/server/bidder/adyoulike/AdyoulikeBidder.java b/src/main/java/org/prebid/server/bidder/adyoulike/AdyoulikeBidder.java index 4c0b4510f80..355562c5075 100644 --- a/src/main/java/org/prebid/server/bidder/adyoulike/AdyoulikeBidder.java +++ b/src/main/java/org/prebid/server/bidder/adyoulike/AdyoulikeBidder.java @@ -8,7 +8,7 @@ import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -99,7 +99,7 @@ private static Imp modifyImp(Imp imp, ExtImpAdyoulike impExt, Price bidFloorPric private Price resolveBidFloor(Imp imp, BidRequest bidRequest) { final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); return BidderUtil.isValidPrice(initialBidFloorPrice) - && !StringUtils.equalsIgnoreCase(initialBidFloorPrice.getCurrency(), BIDDER_CURRENCY) + && !Strings.CI.equals(initialBidFloorPrice.getCurrency(), BIDDER_CURRENCY) ? convertBidFloor(initialBidFloorPrice, imp.getId(), bidRequest) : initialBidFloorPrice; } diff --git a/src/main/java/org/prebid/server/bidder/alkimi/AlkimiBidder.java b/src/main/java/org/prebid/server/bidder/alkimi/AlkimiBidder.java index f1a48242f63..ce4f097d822 100644 --- a/src/main/java/org/prebid/server/bidder/alkimi/AlkimiBidder.java +++ b/src/main/java/org/prebid/server/bidder/alkimi/AlkimiBidder.java @@ -8,7 +8,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -138,8 +138,8 @@ private static Bid resolveMacros(Bid bid) { final String priceAsString = price != null ? price.toPlainString() : "0"; return bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) .build(); } diff --git a/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java b/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java index 71c9cdc4cf4..3f6c5d94e50 100644 --- a/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java +++ b/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java @@ -19,6 +19,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.model.Endpoint; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.appnexus.proto.AppnexusBidExt; @@ -92,8 +93,8 @@ public AppnexusBidder(String endpointUrl, JacksonMapper mapper) { this.endpoint = Uri.of(endpointUrl); - this.headerBiddingSource = ObjectUtils.defaultIfNull(platformId, DEFAULT_PLATFORM_ID); - this.iabCategories = ObjectUtils.defaultIfNull(iabCategories, Collections.emptyMap()); + this.headerBiddingSource = ObjectUtils.getIfNull(platformId, DEFAULT_PLATFORM_ID); + this.iabCategories = ObjectUtils.getIfNull(iabCategories, Collections.emptyMap()); this.mapper = Objects.requireNonNull(mapper); } @@ -126,8 +127,8 @@ public Result>> makeHttpRequests(BidRequest bidRequ } final String requestEndpointName = extractEndpointName(bidRequest); - final boolean isAmp = StringUtils.equals(requestEndpointName, Endpoint.openrtb2_amp.value()); - final boolean isVideo = StringUtils.equals(requestEndpointName, Endpoint.openrtb2_video.value()); + final boolean isAmp = Strings.CS.equals(requestEndpointName, Endpoint.openrtb2_amp.value()); + final boolean isVideo = Strings.CS.equals(requestEndpointName, Endpoint.openrtb2_video.value()); final String url; final BidRequest updatedBidRequest; @@ -171,7 +172,7 @@ private static void validateExtImpAppnexus(ExtImpAppnexus extImpAppnexus, SameValueValidator memberValidator, SameValueValidator generateAdPodIdValidator) { - final int placementId = ObjectUtils.defaultIfNull(extImpAppnexus.getPlacementId(), 0); + final int placementId = ObjectUtils.getIfNull(extImpAppnexus.getPlacementId(), 0); final String member = extImpAppnexus.getMember(); if (placementId == 0 && StringUtils.isAnyBlank(extImpAppnexus.getInvCode(), member)) { throw new PreBidException("No placement or member+invcode provided"); @@ -223,10 +224,10 @@ private static Banner updateBanner(Banner banner, ExtImpAppnexus extImpAppnexus) return position != null || replaceWithFirstFormat ? banner.toBuilder() - .pos(position != null ? position : banner.getPos()) - .w(replaceWithFirstFormat ? firstFormat.getW() : width) - .h(replaceWithFirstFormat ? firstFormat.getH() : height) - .build() + .pos(position != null ? position : banner.getPos()) + .w(replaceWithFirstFormat ? firstFormat.getW() : width) + .h(replaceWithFirstFormat ? firstFormat.getH() : height) + .build() : banner; } diff --git a/src/main/java/org/prebid/server/bidder/aso/AsoBidder.java b/src/main/java/org/prebid/server/bidder/aso/AsoBidder.java index 1f367570ff9..fdf42d11dc7 100644 --- a/src/main/java/org/prebid/server/bidder/aso/AsoBidder.java +++ b/src/main/java/org/prebid/server/bidder/aso/AsoBidder.java @@ -8,7 +8,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.vertx.core.http.HttpMethod; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -141,8 +141,8 @@ private BidderBid makeBid(Bid bid, String currency, List errors) { final String priceAsString = price != null ? price.toPlainString() : "0"; final Bid modifiedBid = bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) .build(); return BidderBid.of(modifiedBid, mediaType, currency); diff --git a/src/main/java/org/prebid/server/bidder/axonix/AxonixBidder.java b/src/main/java/org/prebid/server/bidder/axonix/AxonixBidder.java index c9282e6578e..247eb090f8d 100644 --- a/src/main/java/org/prebid/server/bidder/axonix/AxonixBidder.java +++ b/src/main/java/org/prebid/server/bidder/axonix/AxonixBidder.java @@ -7,7 +7,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -101,8 +101,8 @@ private static Bid resolveMacros(Bid bid) { final String priceAsString = price != null ? price.toPlainString() : "0"; return bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) .build(); } diff --git a/src/main/java/org/prebid/server/bidder/beachfront/BeachfrontBidder.java b/src/main/java/org/prebid/server/bidder/beachfront/BeachfrontBidder.java index 888eeb55c27..b5f125c6617 100644 --- a/src/main/java/org/prebid/server/bidder/beachfront/BeachfrontBidder.java +++ b/src/main/java/org/prebid/server/bidder/beachfront/BeachfrontBidder.java @@ -21,6 +21,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.beachfront.model.BeachfrontBannerRequest; import org.prebid.server.bidder.beachfront.model.BeachfrontResponseSlot; @@ -314,7 +315,7 @@ private static void populateDeviceFields(BeachfrontBannerRequest.BeachfrontBanne } private static int getSecure(String page) { - return StringUtils.contains(page, "https") ? 1 : 0; + return Strings.CS.contains(page, "https") ? 1 : 0; } private static SupplyChain getSchain(BidRequest bidRequest) { @@ -378,8 +379,8 @@ private List getVideoRequests(BidRequest bidRequest, final App app = bidRequest.getApp(); if (app != null && StringUtils.isBlank(app.getDomain()) && StringUtils.isNotBlank(app.getBundle())) { - final String trimmedBundle = StringUtils.removeStart(app.getBundle(), "_"); - final String[] split = StringUtils.removeEnd(trimmedBundle, "_").split("\\."); + final String trimmedBundle = Strings.CS.removeStart(app.getBundle(), "_"); + final String[] split = Strings.CS.removeEnd(trimmedBundle, "_").split("\\."); if (split.length > 1) { bidRequestBuilder.app(app.toBuilder().domain("%s.%s".formatted(split[1], split[0])).build()); diff --git a/src/main/java/org/prebid/server/bidder/beachfront/BeachfrontFloorResolver.java b/src/main/java/org/prebid/server/bidder/beachfront/BeachfrontFloorResolver.java index ff42e8558f8..96685bdbeb7 100644 --- a/src/main/java/org/prebid/server/bidder/beachfront/BeachfrontFloorResolver.java +++ b/src/main/java/org/prebid/server/bidder/beachfront/BeachfrontFloorResolver.java @@ -99,7 +99,7 @@ private static BidFloorResult currencyConversionError(BigDecimal impBidFloor, } private static BidFloorResult proceedWithHigherFloor(BigDecimal extImpBidFloor, BigDecimal convertedBidFloor) { - final BigDecimal resolvedExtImpBidFloor = ObjectUtils.defaultIfNull(extImpBidFloor, BigDecimal.ZERO); + final BigDecimal resolvedExtImpBidFloor = ObjectUtils.getIfNull(extImpBidFloor, BigDecimal.ZERO); if (convertedBidFloor != null && convertedBidFloor.compareTo(resolvedExtImpBidFloor) >= 0) { return BidFloorResult.succeeded(Price.of(DEFAULT_BID_CURRENCY, convertedBidFloor)); } diff --git a/src/main/java/org/prebid/server/bidder/bidstack/BidstackBidder.java b/src/main/java/org/prebid/server/bidder/bidstack/BidstackBidder.java index 0a3997e9074..265182dbdd6 100644 --- a/src/main/java/org/prebid/server/bidder/bidstack/BidstackBidder.java +++ b/src/main/java/org/prebid/server/bidder/bidstack/BidstackBidder.java @@ -9,6 +9,7 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -93,9 +94,9 @@ private Imp updateImp(Imp imp, BidRequest request) { return resolvedBidFloor.isUpdated() ? imp.toBuilder() - .bidfloorcur(BIDDER_CURRENCY) - .bidfloor(resolvedBidFloor.getValue()) - .build() + .bidfloorcur(BIDDER_CURRENCY) + .bidfloor(resolvedBidFloor.getValue()) + .build() : imp; } @@ -113,7 +114,7 @@ private static BidRequest updateBidRequest(BidRequest request, List updated } private static boolean shouldConvertBidFloor(BigDecimal bidFloor, String bidFloorCur) { - return BidderUtil.isValidPrice(bidFloor) && !StringUtils.equalsIgnoreCase(bidFloorCur, BIDDER_CURRENCY); + return BidderUtil.isValidPrice(bidFloor) && !Strings.CI.equals(bidFloorCur, BIDDER_CURRENCY); } private BigDecimal convertBidFloorCurrency(BigDecimal bidFloor, diff --git a/src/main/java/org/prebid/server/bidder/bidtheatre/BidTheatreBidder.java b/src/main/java/org/prebid/server/bidder/bidtheatre/BidTheatreBidder.java index 1e1fc625175..53ae434ed08 100644 --- a/src/main/java/org/prebid/server/bidder/bidtheatre/BidTheatreBidder.java +++ b/src/main/java/org/prebid/server/bidder/bidtheatre/BidTheatreBidder.java @@ -6,7 +6,7 @@ import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -93,8 +93,8 @@ private BidderBid makeBid(Bid bid, String currency, List errors) { final String priceAsString = price != null ? price.toPlainString() : "0"; final Bid modifiedBid = bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) .build(); return BidderBid.of(modifiedBid, mediaType, currency); diff --git a/src/main/java/org/prebid/server/bidder/bidwave/BidwaveBidder.java b/src/main/java/org/prebid/server/bidder/bidwave/BidwaveBidder.java new file mode 100644 index 00000000000..ab602b009d3 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/bidwave/BidwaveBidder.java @@ -0,0 +1,201 @@ +package org.prebid.server.bidder.bidwave; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.apache.commons.collections4.CollectionUtils; +import org.prebid.server.bidder.Bidder; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.Price; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.json.DecodeException; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.ExtRequest; +import org.prebid.server.proto.openrtb.ext.request.bidwave.ExtImpBidwave; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.BidderUtil; +import org.prebid.server.util.HttpUtil; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class BidwaveBidder implements Bidder { + + private static final String BIDWAVE_EXT = "bidwave"; + private static final String PUBLISHER_ID_EXT = "pid"; + private static final String BIDDER_CURRENCY = "USD"; + private static final List DEFAULT_CURRENCY = Collections.singletonList(BIDDER_CURRENCY); + private static final TypeReference> BIDWAVE_EXT_TYPE_REFERENCE = + new TypeReference<>() { + }; + + private final String endpointUrl; + private final CurrencyConversionService currencyConversionService; + private final JacksonMapper mapper; + + public BidwaveBidder(String endpointUrl, + CurrencyConversionService currencyConversionService, + JacksonMapper mapper) { + + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.currencyConversionService = Objects.requireNonNull(currencyConversionService); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public Result>> makeHttpRequests(BidRequest bidRequest) { + final List errors = new ArrayList<>(); + final Map> impsByPublisherId = new LinkedHashMap<>(); + + for (Imp imp : bidRequest.getImp()) { + try { + final String publisherId = parsePublisherId(imp); + final Imp modifiedImp = modifyImpCurrency(imp, bidRequest); + impsByPublisherId.computeIfAbsent(publisherId, ignored -> new ArrayList<>()).add(modifiedImp); + } catch (PreBidException e) { + errors.add(BidderError.badInput(e.getMessage())); + } + } + + final List> requests = impsByPublisherId.entrySet().stream() + .map(entry -> BidderUtil.defaultRequest( + createRequest(bidRequest, entry.getValue(), entry.getKey()), endpointUrl, mapper)) + .toList(); + + return Result.of(requests, errors); + } + + private String parsePublisherId(Imp imp) { + final ExtImpBidwave extImpBidwave; + try { + extImpBidwave = mapper.mapper().convertValue(imp.getExt(), BIDWAVE_EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException("Invalid imp.ext for impression %s. Error Information: %s" + .formatted(imp.getId(), e.getMessage())); + } + + return extImpBidwave.getPublisherId(); + } + + private Imp modifyImpCurrency(Imp imp, BidRequest bidRequest) { + final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); + if (!BidderUtil.shouldConvertBidFloor(initialBidFloorPrice, BIDDER_CURRENCY)) { + return imp; + } + + try { + final BigDecimal convertedBidFloor = currencyConversionService.convertCurrency( + initialBidFloorPrice.getValue(), + bidRequest, + initialBidFloorPrice.getCurrency(), + BIDDER_CURRENCY); + return imp.toBuilder() + .bidfloor(convertedBidFloor) + .bidfloorcur(BIDDER_CURRENCY) + .build(); + } catch (PreBidException e) { + throw new PreBidException( + "expected currency USD for bid floor; unable to convert from %s for imp `%s`" + .formatted(initialBidFloorPrice.getCurrency(), imp.getId())); + } + } + + private BidRequest createRequest(BidRequest bidRequest, List imps, String publisherId) { + return bidRequest.toBuilder() + .imp(imps) + .cur(DEFAULT_CURRENCY) + .ext(createRequestExt(bidRequest.getExt(), publisherId)) + .build(); + } + + private ExtRequest createRequestExt(ExtRequest requestExt, String publisherId) { + final ExtRequest updatedExt = ExtRequest.of(requestExt != null ? requestExt.getPrebid() : null); + if (requestExt != null) { + mapper.fillExtension(updatedExt, requestExt); + } + + final ObjectNode bidwaveExt = mapper.mapper().createObjectNode().put(PUBLISHER_ID_EXT, publisherId); + updatedExt.addProperty(BIDWAVE_EXT, bidwaveExt); + return updatedExt; + } + + @Override + public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + final BidResponse bidResponse; + try { + bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + } catch (DecodeException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + + final List errors = new ArrayList<>(); + final List bids = extractBids(bidResponse, errors); + return Result.of(bids, errors); + } + + private static List extractBids(BidResponse bidResponse, + List errors) { + + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Collections.emptyList(); + } + + final String currency = bidResponse.getCur(); + + return bidResponse.getSeatbid().stream() + .filter(Objects::nonNull) + .map(SeatBid::getBid) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .map(bid -> makeBidderBid(bid, currency, errors)) + .filter(Objects::nonNull) + .toList(); + } + + private static BidderBid makeBidderBid(Bid bid, + String currency, + List errors) { + + final BidType bidType; + try { + bidType = resolveBidType(bid); + } catch (PreBidException e) { + errors.add(BidderError.badServerResponse(e.getMessage())); + return null; + } + + return BidderBid.of(bid, bidType, currency); + } + + private static BidType resolveBidType(Bid bid) { + final Integer markupType = bid.getMtype(); + if (markupType == null) { + throw new PreBidException("Bid must have non-zero MType for impression with ID: \"%s\"" + .formatted(bid.getImpid())); + } + + return switch (markupType) { + case 1 -> BidType.banner; + case 2 -> BidType.video; + default -> throw new PreBidException("Unsupported MType %d for impression with ID: \"%s\"" + .formatted(markupType, bid.getImpid())); + }; + } +} diff --git a/src/main/java/org/prebid/server/bidder/blis/BlisBidder.java b/src/main/java/org/prebid/server/bidder/blis/BlisBidder.java index 2d2989cdd6e..f0e5e9d2b97 100644 --- a/src/main/java/org/prebid/server/bidder/blis/BlisBidder.java +++ b/src/main/java/org/prebid/server/bidder/blis/BlisBidder.java @@ -8,7 +8,7 @@ import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -118,9 +118,9 @@ private static Bid resolveMacros(Bid bid) { final String priceAsString = price != null ? price.toPlainString() : "0"; return bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), AUCTION_PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), AUCTION_PRICE_MACRO, priceAsString)) - .burl(StringUtils.replace(bid.getBurl(), AUCTION_PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), AUCTION_PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), AUCTION_PRICE_MACRO, priceAsString)) + .burl(Strings.CS.replace(bid.getBurl(), AUCTION_PRICE_MACRO, priceAsString)) .build(); } diff --git a/src/main/java/org/prebid/server/bidder/connectad/ConnectAdBidder.java b/src/main/java/org/prebid/server/bidder/connectad/ConnectAdBidder.java index 4c64992184b..1775537018c 100644 --- a/src/main/java/org/prebid/server/bidder/connectad/ConnectAdBidder.java +++ b/src/main/java/org/prebid/server/bidder/connectad/ConnectAdBidder.java @@ -1,12 +1,15 @@ package org.prebid.server.bidder.connectad; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; import com.iab.openrtb.request.Format; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.Site; +import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; @@ -31,13 +34,19 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; public class ConnectAdBidder implements Bidder { private static final TypeReference> CONNECTAD_EXT_TYPE_REFERENCE = new TypeReference<>() { }; + private static final String BIDDER_EXT_KEY = "bidder"; + private static final String NETWORK_ID_FIELD = "networkId"; + private static final String SITE_ID_FIELD = "siteId"; private static final String HTTPS_PREFIX = "https"; private final String endpointUrl; @@ -58,7 +67,7 @@ public Result>> makeHttpRequests(BidRequest request for (Imp imp : request.getImp()) { try { final ExtImpConnectAd impExt = parseImpExt(imp); - final Imp updatedImp = updateImp(imp, secure, impExt.getSiteId(), impExt.getBidFloor()); + final Imp updatedImp = updateImp(imp, secure, impExt); processedImps.add(updatedImp); } catch (PreBidException e) { errors.add(BidderError.badInput(e.getMessage())); @@ -91,27 +100,40 @@ private ExtImpConnectAd parseImpExt(Imp imp) { } catch (IllegalArgumentException e) { throw new PreBidException("Impression id=%s, has invalid Ext".formatted(imp.getId())); } - final String siteId = extImpConnectAd.getSiteId(); - if (siteId == null) { + if (extImpConnectAd.getSiteId() == null) { throw new PreBidException("Impression id=%s, has no siteId present".formatted(imp.getId())); } return extImpConnectAd; } - private Imp updateImp(Imp imp, Integer secure, String siteId, BigDecimal bidFloor) { + private static Imp updateImp(Imp imp, int secure, ExtImpConnectAd extImpConnectAd) { + final BigDecimal bidFloor = extImpConnectAd.getBidFloor(); final boolean isValidBidFloor = BidderUtil.isValidPrice(bidFloor); return imp.toBuilder() .banner(updateBanner(imp.getBanner())) - .tagid(siteId) + .tagid(String.valueOf(extImpConnectAd.getSiteId())) .secure(secure) .bidfloor(isValidBidFloor ? bidFloor : imp.getBidfloor()) .bidfloorcur(isValidBidFloor ? "USD" : imp.getBidfloorcur()) + .ext(modifyImpExt(imp.getExt())) .build(); } + private static ObjectNode modifyImpExt(ObjectNode impExt) { + final ObjectNode modifiedExt = impExt.deepCopy(); + final JsonNode bidder = modifiedExt.get(BIDDER_EXT_KEY); + if (bidder.has(NETWORK_ID_FIELD)) { + modifiedExt.set(NETWORK_ID_FIELD, bidder.get(NETWORK_ID_FIELD)); + } + if (bidder.has(SITE_ID_FIELD)) { + modifiedExt.set(SITE_ID_FIELD, bidder.get(SITE_ID_FIELD)); + } + return modifiedExt; + } + private static Banner updateBanner(Banner banner) { if (banner == null) { - throw new PreBidException("We need a Banner Object in the request"); + return null; } if (banner.getW() != null || banner.getH() != null) { @@ -153,24 +175,41 @@ private static MultiMap resolveHeaders(Device device) { public final Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); - return Result.withValues(extractBids(bidResponse)); + return Result.withValues(extractBids(bidResponse, bidRequest)); } catch (DecodeException | PreBidException e) { return Result.withError(BidderError.badServerResponse(e.getMessage())); } } - private List extractBids(BidResponse bidResponse) { + private List extractBids(BidResponse bidResponse, BidRequest bidRequest) { if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { return Collections.emptyList(); } + final Map impIdToImp = bidRequest.getImp().stream() + .collect(Collectors.toMap(Imp::getId, Function.identity())); + return bidResponse.getSeatbid().stream() .filter(Objects::nonNull) .map(SeatBid::getBid) .filter(Objects::nonNull) .flatMap(Collection::stream) .filter(Objects::nonNull) - .map(bid -> BidderBid.of(bid, BidType.banner, bidResponse.getCur())) + .map(bid -> BidderBid.of(bid, getBidType(bid, impIdToImp), bidResponse.getCur())) .toList(); } + + private static BidType getBidType(Bid bid, Map impIdToImp) { + final Integer mType = bid.getMtype(); + if (mType == null) { + return BidderUtil.getBidType(bid, impIdToImp); + } + + return switch (mType) { + case 2 -> BidType.video; + case 3 -> BidType.audio; + case 4 -> BidType.xNative; + default -> BidType.banner; + }; + } } diff --git a/src/main/java/org/prebid/server/bidder/dianomi/DianomiBidder.java b/src/main/java/org/prebid/server/bidder/dianomi/DianomiBidder.java index cd911549165..9d39a981272 100644 --- a/src/main/java/org/prebid/server/bidder/dianomi/DianomiBidder.java +++ b/src/main/java/org/prebid/server/bidder/dianomi/DianomiBidder.java @@ -85,7 +85,7 @@ private ExtImpDianomi parseImpExt(Imp imp) { } private BidRequest modifyBidRequest(BidRequest bidRequest, List imps, String priceType) { - final ExtRequest extRequest = ObjectUtils.defaultIfNull(bidRequest.getExt(), ExtRequest.empty()); + final ExtRequest extRequest = ObjectUtils.getIfNull(bidRequest.getExt(), ExtRequest.empty()); final ExtRequest modifiedExtRequest = StringUtils.isNotEmpty(priceType) ? modifyExtRequest(extRequest, priceType) : extRequest; diff --git a/src/main/java/org/prebid/server/bidder/displayio/DisplayioBidder.java b/src/main/java/org/prebid/server/bidder/displayio/DisplayioBidder.java index 8ea231bad30..7079cbe2213 100644 --- a/src/main/java/org/prebid/server/bidder/displayio/DisplayioBidder.java +++ b/src/main/java/org/prebid/server/bidder/displayio/DisplayioBidder.java @@ -9,6 +9,7 @@ import io.vertx.core.MultiMap; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -105,7 +106,7 @@ private BigDecimal resolveBidFloor(BidRequest bidRequest, Imp imp) { if (BidderUtil.isValidPrice(bidFloor) && StringUtils.isNotBlank(bidFloorCurrency) - && !StringUtils.equalsIgnoreCase(bidFloorCurrency, BIDDER_CURRENCY)) { + && !Strings.CI.equals(bidFloorCurrency, BIDDER_CURRENCY)) { return currencyConversionService.convertCurrency(bidFloor, bidRequest, bidFloorCurrency, BIDDER_CURRENCY); } diff --git a/src/main/java/org/prebid/server/bidder/dmx/DmxBidder.java b/src/main/java/org/prebid/server/bidder/dmx/DmxBidder.java index d311a6f9296..85db83c9aa3 100644 --- a/src/main/java/org/prebid/server/bidder/dmx/DmxBidder.java +++ b/src/main/java/org/prebid/server/bidder/dmx/DmxBidder.java @@ -260,7 +260,7 @@ private Publisher modifyPublisher(Publisher publisher, String updatedPublisherId .build(); } else { return publisher.toBuilder() - .id(ObjectUtils.defaultIfNull(publisher.getId(), updatedPublisherId)) + .id(ObjectUtils.getIfNull(publisher.getId(), updatedPublisherId)) .ext(extPublisher) .build(); } diff --git a/src/main/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidder.java b/src/main/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidder.java index f3ebcedb617..356bc0cf86a 100644 --- a/src/main/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidder.java +++ b/src/main/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidder.java @@ -16,6 +16,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -266,7 +267,7 @@ private static List bidsFromResponse(BidResponse bidResponse) { } private static BidType getBidType(String bidAdm) { - return StringUtils.containsAny(bidAdm, " { + + private static final TypeReference> ESKIMI_EXT_TYPE_REFERENCE = + new TypeReference<>() { + }; + + private final String endpointUrl; + private final JacksonMapper mapper; + + public EskimiBidder(String endpointUrl, JacksonMapper mapper) { + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public Result>> makeHttpRequests(BidRequest request) { + final ExtImpEskimi firstExt; + try { + validateRequest(request); + firstExt = parseImpExt(request.getImp().getFirst()); + } catch (PreBidException e) { + return Result.withError(BidderError.badInput(e.getMessage())); + } + + final List validImps = new ArrayList<>(); + final List errors = new ArrayList<>(); + + for (Imp imp : request.getImp()) { + try { + validImps.add(modifyImp(imp)); + } catch (PreBidException e) { + errors.add(BidderError.badInput(e.getMessage())); + } + } + + final BidRequest outgoingRequest = modifyBidRequest(request, validImps, firstExt); + + return Result.of( + Collections.singletonList(BidderUtil.defaultRequest(outgoingRequest, endpointUrl, mapper)), errors); + } + + private static void validateRequest(BidRequest request) { + if (request.getSite() == null && request.getApp() == null) { + throw new PreBidException("request must contain either site or app"); + } + } + + private ExtImpEskimi parseImpExt(Imp imp) { + try { + return mapper.mapper().convertValue(imp.getExt(), ESKIMI_EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException("invalid imp.ext for imp %s: %s".formatted(imp.getId(), e.getMessage())); + } + } + + private Imp modifyImp(Imp imp) { + final ExtImpEskimi extImp = parseImpExt(imp); + final List bAttr = extImp.getBattr(); + final Price price = resolvePrice(imp, extImp); + + return imp.toBuilder() + .banner(imp.getBanner() != null ? modifyBanner(imp.getBanner(), bAttr) : null) + .video(imp.getVideo() != null ? modifyVideo(imp.getVideo(), bAttr) : null) + .bidfloor(price.getValue()) + .bidfloorcur(price.getCurrency()) + .secure(ObjectUtils.getIfNull(imp.getSecure(), 1)) + .build(); + } + + private static Banner modifyBanner(Banner banner, List bAttr) { + return CollectionUtils.isNotEmpty(bAttr) && CollectionUtils.isEmpty(banner.getBattr()) + ? banner.toBuilder().battr(bAttr).build() + : banner; + } + + private static Video modifyVideo(Video video, List bAttr) { + return CollectionUtils.isNotEmpty(bAttr) && CollectionUtils.isEmpty(video.getBattr()) + ? video.toBuilder().battr(bAttr).build() + : video; + } + + private static Price resolvePrice(Imp imp, ExtImpEskimi extImp) { + final BigDecimal originalPrice = imp.getBidfloor(); + final String originalCurrency = imp.getBidfloorcur(); + + final BigDecimal newPrice = extImp.getBidFloor(); + + return !BidderUtil.isValidPrice(originalPrice) && BidderUtil.isValidPrice(newPrice) + ? Price.of(StringUtils.defaultIfBlank(extImp.getBidFloorCur(), originalCurrency), newPrice) + : Price.of(originalCurrency, originalPrice); + } + + private static BidRequest modifyBidRequest(BidRequest request, List validImps, ExtImpEskimi ext) { + final Site modifiedSite = request.getSite() != null + ? modifySite(request.getSite(), ext.getPlacementId()) + : null; + final App modifiedApp = modifiedSite == null + ? modifyApp(request.getApp(), ext.getPlacementId()) + : request.getApp(); + + return request.toBuilder() + .imp(validImps) + .site(modifiedSite) + .app(modifiedApp) + .bcat(CollectionUtils.isEmpty(request.getBcat()) ? ext.getBcat() : request.getBcat()) + .badv(CollectionUtils.isEmpty(request.getBadv()) ? ext.getBadv() : request.getBadv()) + .bapp(CollectionUtils.isEmpty(request.getBapp()) ? ext.getBapp() : request.getBapp()) + .build(); + } + + private static Site modifySite(Site site, Integer placementId) { + return site.toBuilder() + .ext(addPlacementId(ObjectUtils.getIfNull(site.getExt(), () -> ExtSite.of(null, null)), placementId)) + .build(); + } + + private static App modifyApp(App app, Integer placementId) { + return app.toBuilder() + .ext(addPlacementId(ObjectUtils.getIfNull(app.getExt(), () -> ExtApp.of(null, null)), placementId)) + .build(); + } + + private static T addPlacementId(T ext, Integer placementId) { + ext.addProperty("placementId", IntNode.valueOf(placementId)); + return ext; + } + + @Override + public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + try { + final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + final List errors = new ArrayList<>(); + return Result.of(extractBids(httpCall.getRequest().getPayload(), bidResponse, errors), errors); + } catch (DecodeException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + } + + private static List extractBids(BidRequest bidRequest, + BidResponse bidResponse, + List errors) { + + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Collections.emptyList(); + } + + return bidResponse.getSeatbid().stream() + .filter(Objects::nonNull) + .map(SeatBid::getBid) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .map(bid -> createBidderBid(bid, bidRequest.getImp(), bidResponse.getCur(), errors)) + .filter(Objects::nonNull) + .toList(); + } + + private static BidderBid createBidderBid(Bid bid, + List imps, + String currency, + List errors) { + + try { + return BidderBid.of(bid, getBidType(bid, imps), currency); + } catch (PreBidException e) { + errors.add(BidderError.badServerResponse(e.getMessage())); + return null; + } + } + + private static BidType getBidType(Bid bid, List imps) { + return Optional.ofNullable(bidTypeFromMtype(bid)) + .orElseGet(() -> bidTypeFromImp(bid.getImpid(), imps)); + } + + private static BidType bidTypeFromMtype(Bid bid) { + return switch (bid.getMtype()) { + case null -> null; + case 0 -> null; + case 1 -> BidType.banner; + case 2 -> BidType.video; + default -> throw new PreBidException( + "unsupported bid.mtype %d for impression %s (banner and video only)" + .formatted(bid.getMtype(), bid.getImpid())); + }; + } + + private static BidType bidTypeFromImp(String impId, List imps) { + for (Imp imp : imps) { + if (!imp.getId().equals(impId)) { + continue; + } + + final boolean hasBanner = imp.getBanner() != null; + final boolean hasVideo = imp.getVideo() != null; + + if (hasBanner && hasVideo) { + throw new PreBidException( + "bid for multi-format imp %s requires bid.mtype to disambiguate".formatted(impId)); + } + if (hasBanner) { + return BidType.banner; + } + if (hasVideo) { + return BidType.video; + } + + throw new PreBidException( + "unsupported media type for impression %s (banner and video only)".formatted(impId)); + } + + throw new PreBidException( + "unable to resolve media type for impression %s".formatted(impId)); + } +} diff --git a/src/main/java/org/prebid/server/bidder/evolution/EvolutionBidder.java b/src/main/java/org/prebid/server/bidder/evolution/EvolutionBidder.java index 9bc64b3c12b..62a90882099 100644 --- a/src/main/java/org/prebid/server/bidder/evolution/EvolutionBidder.java +++ b/src/main/java/org/prebid/server/bidder/evolution/EvolutionBidder.java @@ -67,7 +67,7 @@ private List bidsFromResponse(BidResponse bidResponse) { private BidType getBidMediaType(JsonNode bidExt) { final JsonNode mediaTypeNode = bidExt != null ? bidExt.get("mediaType") : null; try { - return ObjectUtils.defaultIfNull(mapper.mapper() + return ObjectUtils.getIfNull(mapper.mapper() .convertValue(mediaTypeNode, BidType.class), BidType.banner); } catch (IllegalArgumentException e) { return BidType.banner; diff --git a/src/main/java/org/prebid/server/bidder/floxis/FloxisBidder.java b/src/main/java/org/prebid/server/bidder/floxis/FloxisBidder.java new file mode 100644 index 00000000000..7e51b073b12 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/floxis/FloxisBidder.java @@ -0,0 +1,207 @@ +package org.prebid.server.bidder.floxis; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.prebid.server.bidder.Bidder; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.json.DecodeException; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.floxis.ExtImpFloxis; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.BidderUtil; +import org.prebid.server.util.Uri; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +public class FloxisBidder implements Bidder { + + private static final TypeReference> FLOXIS_EXT_TYPE_REFERENCE = + new TypeReference<>() { + }; + + private static final String HOST_MACRO = "Host"; + private static final String SEAT_MACRO = "SeatId"; + + private static final String DEFAULT_REGION = "us-e"; + private static final String DEFAULT_PARTNER = "floxis"; + + private final Uri endpointUrl; + private final JacksonMapper mapper; + + public FloxisBidder(String endpointUrl, JacksonMapper mapper) { + this.endpointUrl = Uri.of(endpointUrl); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public Result>> makeHttpRequests(BidRequest request) { + final List errors = new ArrayList<>(); + final Map> impsByHost = new LinkedHashMap<>(); + + for (Imp imp : request.getImp()) { + final ExtImpFloxis impExt; + try { + impExt = parseImpExt(imp); + } catch (PreBidException e) { + errors.add(BidderError.badInput(e.getMessage())); + continue; + } + + impsByHost.computeIfAbsent( + new HostId(impExt.getSeat(), resolveBidHost(impExt)), key -> new ArrayList<>()) + .add(imp); + } + + final List> httpRequests = impsByHost.entrySet().stream() + .map(entry -> BidderUtil.defaultRequest( + request.toBuilder().imp(entry.getValue()).build(), + resolveUrl(entry.getKey()), + mapper)) + .toList(); + + return Result.of(httpRequests, errors); + } + + private ExtImpFloxis parseImpExt(Imp imp) { + final ExtImpFloxis impExt; + try { + impExt = mapper.mapper().convertValue(imp.getExt(), FLOXIS_EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException("invalid imp.ext.bidder for imp %s: %s".formatted(imp.getId(), e.getMessage())); + } + + final String region = StringUtils.isBlank(impExt.getRegion()) + ? DEFAULT_REGION + : impExt.getRegion().toLowerCase(Locale.ROOT); + final String partner = StringUtils.isBlank(impExt.getPartner()) + ? DEFAULT_PARTNER + : impExt.getPartner().toLowerCase(Locale.ROOT); + + return ExtImpFloxis.of(impExt.getSeat(), region, partner); + } + + private String resolveUrl(HostId hostId) { + return endpointUrl + .replaceMacro(HOST_MACRO, hostId.host()) + .replaceMacro(SEAT_MACRO, hostId.seat()) + .expand(); + } + + private static String resolveBidHost(ExtImpFloxis impExt) { + final String partner = impExt.getPartner(); + final String region = impExt.getRegion(); + return partner.equals(DEFAULT_PARTNER) ? region : partner + "-" + region; + } + + @Override + public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + try { + final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + final List errors = new ArrayList<>(); + final List bidderBids = extractBids(bidResponse, bidRequest.getImp(), errors); + return Result.of(bidderBids, errors); + } catch (DecodeException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + } + + private static List extractBids(BidResponse bidResponse, List imps, List errors) { + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Collections.emptyList(); + } + + return bidResponse.getSeatbid().stream() + .filter(Objects::nonNull) + .map(SeatBid::getBid) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .map(bid -> makeBidderBid(bid, imps, bidResponse.getCur(), errors)) + .filter(Objects::nonNull) + .toList(); + } + + private static BidderBid makeBidderBid(Bid bid, List imps, String currency, List errors) { + try { + return BidderBid.of(bid, getMediaTypeForBid(imps, bid), currency); + } catch (PreBidException e) { + errors.add(BidderError.badServerResponse(e.getMessage())); + return null; + } + } + + private static BidType getMediaTypeForBid(List imps, Bid bid) { + final Integer mtype = bid.getMtype(); + if (mtype != null && mtype != 0) { + return switch (mtype) { + case 1 -> BidType.banner; + case 2 -> BidType.video; + case 3 -> BidType.audio; + case 4 -> BidType.xNative; + default -> throw new PreBidException( + "unsupported bid.mtype %d for impression %s".formatted(mtype, bid.getImpid())); + }; + } + + final Imp imp = imps.stream() + .filter(currentImp -> Objects.equals(currentImp.getId(), bid.getImpid())) + .findFirst() + .orElseThrow(() -> new PreBidException( + "unable to find impression %s for bid".formatted(bid.getImpid()))); + + if (countFormats(imp) != 1) { + throw new PreBidException( + "unable to resolve a single media type for impression %s; set bid.mtype" + .formatted(bid.getImpid())); + } + + if (imp.getBanner() != null) { + return BidType.banner; + } else if (imp.getVideo() != null) { + return BidType.video; + } else if (imp.getAudio() != null) { + return BidType.audio; + } else { + return BidType.xNative; + } + } + + private static int countFormats(Imp imp) { + int formats = 0; + if (imp.getBanner() != null) { + formats++; + } + if (imp.getVideo() != null) { + formats++; + } + if (imp.getAudio() != null) { + formats++; + } + if (imp.getXNative() != null) { + formats++; + } + return formats; + } + + private record HostId(String seat, String host) { + } +} diff --git a/src/main/java/org/prebid/server/bidder/gamma/GammaBidder.java b/src/main/java/org/prebid/server/bidder/gamma/GammaBidder.java index 73a7d6ec574..8c6fd56dc59 100644 --- a/src/main/java/org/prebid/server/bidder/gamma/GammaBidder.java +++ b/src/main/java/org/prebid/server/bidder/gamma/GammaBidder.java @@ -142,7 +142,7 @@ private String makeUri(ExtImpGamma extImpGamma, String impId, Device device, App .addQueryParam("id", extImpGamma.getId()) .addQueryParam("zid", extImpGamma.getZid()) .addQueryParam("wid", extImpGamma.getWid()) - .addQueryParam("bidid", ObjectUtils.defaultIfNull(impId, "")) + .addQueryParam("bidid", ObjectUtils.getIfNull(impId, "")) .addQueryParam("hb", "pbmobile"); if (device != null) { diff --git a/src/main/java/org/prebid/server/bidder/grid/GridBidder.java b/src/main/java/org/prebid/server/bidder/grid/GridBidder.java index 6f5b0e93b35..6c67eef66dd 100644 --- a/src/main/java/org/prebid/server/bidder/grid/GridBidder.java +++ b/src/main/java/org/prebid/server/bidder/grid/GridBidder.java @@ -193,8 +193,8 @@ private Keywords buildBidRequestExtKeywords(String userKeywords, Keywords firstImpExtKeywords, Keywords requestExtKeywords) { - final String resolvedUserKeywords = ObjectUtils.defaultIfNull(userKeywords, ""); - final String resolvedSiteKeywords = ObjectUtils.defaultIfNull(siteKeywords, ""); + final String resolvedUserKeywords = ObjectUtils.getIfNull(userKeywords, ""); + final String resolvedSiteKeywords = ObjectUtils.getIfNull(siteKeywords, ""); return gridKeywordsProcessor.merge( gridKeywordsProcessor.resolveKeywordsFromOpenRtb(resolvedUserKeywords, resolvedSiteKeywords), @@ -268,7 +268,7 @@ private String modifyAdm(ObjectNode bidNode, Bid bid) { } private ObjectNode modifyBidExt(ObjectNode gridBid) { - final String demandSource = ObjectUtils.defaultIfNull(gridBid, MissingNode.getInstance()) + final String demandSource = ObjectUtils.getIfNull(gridBid, MissingNode.getInstance()) .at("/ext/bidder/grid/demandSource") .textValue(); if (StringUtils.isEmpty(demandSource)) { diff --git a/src/main/java/org/prebid/server/bidder/huaweiads/HuaweiAdmBuilder.java b/src/main/java/org/prebid/server/bidder/huaweiads/HuaweiAdmBuilder.java index 5c4bb8f2235..7a9a0dcd41d 100644 --- a/src/main/java/org/prebid/server/bidder/huaweiads/HuaweiAdmBuilder.java +++ b/src/main/java/org/prebid/server/bidder/huaweiads/HuaweiAdmBuilder.java @@ -79,7 +79,7 @@ public HuaweiAdm buildBanner(AdsType adType, Content content) { return switch (creativeType) { case VIDEO, VIDEO_TEXT, VIDEO_WITH_PICTURES_TEXT -> buildVideo(adType, content, null); case TEXT, BIG_PICTURE, BIG_PICTURE_2, SMALL_PICTURE, - THREE_SMALL_PICTURES_TEXT, ICON_TEXT, GIF -> buildPicture(content); + THREE_SMALL_PICTURES_TEXT, ICON_TEXT, GIF -> buildPicture(content); default -> throw new PreBidException("no banner support creativetype"); }; } @@ -162,7 +162,7 @@ public HuaweiAdm buildVideo(AdsType adType, Content content, Video video) { final MonitorEventType eventType = MonitorEventType.of(monitor.getEventType()); switch (eventType) { case USER_CLOSE, PLAY_START, PLAY_END, PLAY_RESUME, - PLAY_PAUSE, SOUND_CLICK_OFF, SOUND_CLICK_ON -> + PLAY_PAUSE, SOUND_CLICK_OFF, SOUND_CLICK_ON -> trackingEvents.add(getVastEventTrackingUrls(urls, eventType)); case VAST_ERROR -> errorTracking.add(getVastImpClickErrorTrackingUrls(urls, eventType)); case IMP -> dspImpTracking.add(getVastImpClickErrorTrackingUrls(urls, eventType)); @@ -200,7 +200,7 @@ private static String makeUrl(MonitorEventType eventType, String url) { private static String getVastEventTrackingUrls(List urls, MonitorEventType eventType) { return urls.stream().map(eventUrl -> eventType == MonitorEventType.USER_CLOSE ? "" - + "" + + "" : "") .collect(Collectors.joining()); } @@ -448,8 +448,8 @@ private static DataObject buildDataObject(MetaData metaData, Integer assetDataTy final String value = isDataAssetType ? metaData.getDescription() : isDataAssetCtaTextType - ? metaData.getCta() - : null; + ? metaData.getCta() + : null; return DataObject.builder() .value(decode(value)) diff --git a/src/main/java/org/prebid/server/bidder/huaweiads/HuaweiDeviceBuilder.java b/src/main/java/org/prebid/server/bidder/huaweiads/HuaweiDeviceBuilder.java index ab980027072..6290ae751e4 100644 --- a/src/main/java/org/prebid/server/bidder/huaweiads/HuaweiDeviceBuilder.java +++ b/src/main/java/org/prebid/server/bidder/huaweiads/HuaweiDeviceBuilder.java @@ -77,8 +77,8 @@ private Device makeDeviceWithDeviceId(com.iab.openrtb.request.Device device, Use } final String gaid = isGaidEmpty - ? deviceIfa.orElseThrow(() -> new PreBidException("getDeviceID: openRTBRequest.User.Ext is nil " - + "and device.Gaid is not specified.")) + ? deviceIfa.orElseThrow(() -> new PreBidException( + "getDeviceID: openRTBRequest.User.Ext is nil and device.Gaid is not specified.")) : userData.getGaid().getFirst(); final String oaid = isOaidEmpty ? null : userData.getOaid().getFirst(); final String imei = isImeiEmpty ? null : userData.getImei().getFirst(); diff --git a/src/main/java/org/prebid/server/bidder/impactify/ImpactifyBidder.java b/src/main/java/org/prebid/server/bidder/impactify/ImpactifyBidder.java index 4f52dd87765..28aa64c790a 100644 --- a/src/main/java/org/prebid/server/bidder/impactify/ImpactifyBidder.java +++ b/src/main/java/org/prebid/server/bidder/impactify/ImpactifyBidder.java @@ -12,6 +12,7 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -84,7 +85,7 @@ private BigDecimal resolveBidFloor(BidRequest request, Imp imp) { } private static boolean shouldConvertBidFloor(BigDecimal bidFloor, String bidFloorCur) { - return BidderUtil.isValidPrice(bidFloor) && !StringUtils.equalsIgnoreCase(bidFloorCur, BIDDER_CURRENCY); + return BidderUtil.isValidPrice(bidFloor) && !Strings.CI.equals(bidFloorCur, BIDDER_CURRENCY); } private BigDecimal convertBidFloorCurrency(BigDecimal bidFloor, diff --git a/src/main/java/org/prebid/server/bidder/iqx/IqxBidder.java b/src/main/java/org/prebid/server/bidder/iqx/IqxBidder.java index 26704bbaa75..e4d5d0af95a 100644 --- a/src/main/java/org/prebid/server/bidder/iqx/IqxBidder.java +++ b/src/main/java/org/prebid/server/bidder/iqx/IqxBidder.java @@ -127,7 +127,7 @@ private static BidderBid makeBid(Bid bid, String currency, List err } private static BidType getBidType(Bid bid) { - return switch (ObjectUtils.defaultIfNull(bid.getMtype(), 0)) { + return switch (ObjectUtils.getIfNull(bid.getMtype(), 0)) { case 1 -> BidType.banner; case 2 -> BidType.video; case 4 -> BidType.xNative; diff --git a/src/main/java/org/prebid/server/bidder/jixie/JixieBidder.java b/src/main/java/org/prebid/server/bidder/jixie/JixieBidder.java index 41096948172..a556815063e 100644 --- a/src/main/java/org/prebid/server/bidder/jixie/JixieBidder.java +++ b/src/main/java/org/prebid/server/bidder/jixie/JixieBidder.java @@ -8,7 +8,7 @@ import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -90,7 +90,7 @@ private static List bidsFromResponse(BidResponse bidResponse) { } private static BidType getBidType(String adm) { - return StringUtils.containsAny(adm, " extractTargeting(ObjectNode extBidBidder) { final List targetings = rp != null ? rp.getTargeting() : null; return targetings != null ? targetings.stream() - .filter(targeting -> !CollectionUtils.isEmpty(targeting.getValues())) - .collect(Collectors.toMap(MagniteTargeting::getKey, targeting -> targeting.getValues().getFirst())) + .filter(targeting -> !CollectionUtils.isEmpty(targeting.getValues())) + .collect(Collectors.toMap(MagniteTargeting::getKey, targeting -> targeting.getValues().getFirst())) : Collections.emptyMap(); } @@ -498,7 +499,7 @@ private Imp makeImp(Imp imp, final List priceFloorsWarnings = new ArrayList<>(); final PriceFloorResult priceFloorResult = resolvePriceFloors(bidRequest, imp, impType, priceFloorsWarnings); - final Set resolvedFormats = ObjectUtils.defaultIfNull(extImpMagnite.getFormats(), formats); + final Set resolvedFormats = ObjectUtils.getIfNull(extImpMagnite.getFormats(), formats); final BigDecimal ipfFloor = ObjectUtil.getIfNotNull(priceFloorResult, PriceFloorResult::getFloorValue); final String ipfCurrency = ipfFloor != null @@ -1028,7 +1029,7 @@ private Banner makeBanner(Imp imp) { private Native makeNative(Imp imp) { final Native xNative = imp.getXNative(); final String version = ObjectUtil.getIfNotNull(xNative, Native::getVer); - if (StringUtils.equalsAny(version, "1.0", "1.1")) { + if (Strings.CS.equalsAny(version, "1.0", "1.1")) { return xNative; } final String nativeRequest = xNative.getRequest(); @@ -1115,7 +1116,7 @@ private User makeUser(User user, ExtImpMagnite magniteImpExt) { final User.UserBuilder userBuilder = user != null ? user.toBuilder() : User.builder(); return userBuilder - .id(ObjectUtils.defaultIfNull(resolvedId, userId)) + .id(ObjectUtils.getIfNull(resolvedId, userId)) .gender(null) .yob(null) .geo(null) @@ -1294,11 +1295,13 @@ private void processWarnings(List errors, List priceFloorsW } private Device makeDevice(Device device) { - return device == null ? null : device.toBuilder() - .ext(mapper.fillExtension( - ExtDevice.empty(), - MagniteDeviceExt.of(MagniteDeviceExtRp.of(device.getPxratio())))) - .build(); + return device == null + ? null + : device.toBuilder() + .ext(mapper.fillExtension( + ExtDevice.empty(), + MagniteDeviceExt.of(MagniteDeviceExtRp.of(device.getPxratio())))) + .build(); } private Site makeSite(Site site, String impLanguage, ExtImpMagnite magniteImpExt) { @@ -1308,13 +1311,13 @@ private Site makeSite(Site site, String impLanguage, ExtImpMagnite magniteImpExt return site == null ? Site.builder() - .content(makeSiteContent(null, impLanguage)) - .build() + .content(makeSiteContent(null, impLanguage)) + .build() : site.toBuilder() - .publisher(makePublisher(magniteImpExt)) - .content(makeSiteContent(site.getContent(), impLanguage)) - .ext(makeSiteExt(site, magniteImpExt)) - .build(); + .publisher(makePublisher(magniteImpExt)) + .content(makeSiteContent(site.getContent(), impLanguage)) + .ext(makeSiteExt(site, magniteImpExt)) + .build(); } private static Content makeSiteContent(Content siteContent, String impLanguage) { @@ -1327,11 +1330,11 @@ private static Content makeSiteContent(Content siteContent, String impLanguage) return resolvedLanguage != null || hasDataToRemove ? Optional.ofNullable(siteContent) - .map(Content::toBuilder) - .orElseGet(Content::builder) - .data(null) - .language(resolvedLanguage != null ? resolvedLanguage : contentLanguage) - .build() + .map(Content::toBuilder) + .orElseGet(Content::builder) + .data(null) + .language(resolvedLanguage != null ? resolvedLanguage : contentLanguage) + .build() : siteContent; } @@ -1376,10 +1379,12 @@ private ObjectNode existingMagniteSiteExtRpTargetOrEmptyNode(ExtSite siteExt) { } private App makeApp(App app, ExtImpMagnite magniteImpExt) { - return app == null ? null : app.toBuilder() - .publisher(makePublisher(magniteImpExt)) - .ext(makeAppExt(magniteImpExt)) - .build(); + return app == null + ? null + : app.toBuilder() + .publisher(makePublisher(magniteImpExt)) + .ext(makeAppExt(magniteImpExt)) + .build(); } private ExtApp makeAppExt(ExtImpMagnite magniteImpExt) { @@ -1565,7 +1570,7 @@ private Bid updateBid(MagniteBid bid, } // Unconditionally set price if coming from CPM override - final Float cpmOverride = ObjectUtils.defaultIfNull(cpmOverrideFromImp(imp), cpmOverrideFromRequest); + final Float cpmOverride = ObjectUtils.getIfNull(cpmOverrideFromImp(imp), cpmOverrideFromRequest); final BigDecimal bidPrice = cpmOverride != null ? new BigDecimal(String.valueOf(cpmOverride)) : bid.getPrice(); @@ -1683,11 +1688,11 @@ private static Integer convertToInt(JsonNode jsonNode) { private String resolveBidId(Imp magniteImp, MagniteBid bid) { return generateBidId ? Optional.ofNullable(magniteImp) - .map(Imp::getExt) - .map(ext -> ext.get("rp")) - .map(rp -> rp.get("pb_bid_id")) - .map(JsonNode::asText) - .orElse(bid.getId()) + .map(Imp::getExt) + .map(ext -> ext.get("rp")) + .map(rp -> rp.get("pb_bid_id")) + .map(JsonNode::asText) + .orElse(bid.getId()) : bid.getId(); } diff --git a/src/main/java/org/prebid/server/bidder/marsmedia/MarsmediaBidder.java b/src/main/java/org/prebid/server/bidder/marsmedia/MarsmediaBidder.java index 5348053bc8c..9fbc0ba872e 100644 --- a/src/main/java/org/prebid/server/bidder/marsmedia/MarsmediaBidder.java +++ b/src/main/java/org/prebid/server/bidder/marsmedia/MarsmediaBidder.java @@ -112,8 +112,8 @@ private static BidRequest createRequest(BidRequest request) { private static Banner updateBanner(Banner banner) { final Format firstFormat = banner.getFormat().getFirst(); return banner.toBuilder() - .w(ObjectUtils.defaultIfNull(firstFormat.getW(), 0)) - .h(ObjectUtils.defaultIfNull(firstFormat.getH(), 0)) + .w(ObjectUtils.getIfNull(firstFormat.getW(), 0)) + .h(ObjectUtils.getIfNull(firstFormat.getH(), 0)) .build(); } @@ -148,10 +148,11 @@ private static List extractBids(BidResponse bidResponse, BidRequest b private static List bidsFromResponse(List seatbid, List imps, String currency) { final SeatBid firstSeatBid = seatbid.getFirst(); - return firstSeatBid != null ? firstSeatBid.getBid().stream() - .filter(Objects::nonNull) - .map(bid -> BidderBid.of(bid, getBidType(bid.getImpid(), imps), currency)) - .toList() + return firstSeatBid != null + ? firstSeatBid.getBid().stream() + .filter(Objects::nonNull) + .map(bid -> BidderBid.of(bid, getBidType(bid.getImpid(), imps), currency)) + .toList() : Collections.emptyList(); } diff --git a/src/main/java/org/prebid/server/bidder/mediasquare/MediasquareBidder.java b/src/main/java/org/prebid/server/bidder/mediasquare/MediasquareBidder.java index 18c9fca362b..34dc19bd19b 100644 --- a/src/main/java/org/prebid/server/bidder/mediasquare/MediasquareBidder.java +++ b/src/main/java/org/prebid/server/bidder/mediasquare/MediasquareBidder.java @@ -175,7 +175,7 @@ private static Map makeFloors(MediasquareFloor floor, } if (banner != null) { - for (List format: banner.getSizes()) { + for (List format : banner.getSizes()) { floors.put(SIZE_FORMAT.formatted(format.get(0), format.get(1)), floor); } } diff --git a/src/main/java/org/prebid/server/bidder/melozen/MeloZenBidder.java b/src/main/java/org/prebid/server/bidder/melozen/MeloZenBidder.java index 58e1b10b68d..721860abcc2 100644 --- a/src/main/java/org/prebid/server/bidder/melozen/MeloZenBidder.java +++ b/src/main/java/org/prebid/server/bidder/melozen/MeloZenBidder.java @@ -14,6 +14,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -104,7 +105,7 @@ private Price resolveBidFloor(BidRequest bidRequest, Imp imp) { if (BidderUtil.isValidPrice(bidFloor) && StringUtils.isNotBlank(bidFloorCurrency) - && !StringUtils.equalsIgnoreCase(bidFloorCurrency, BIDDER_CURRENCY)) { + && !Strings.CI.equals(bidFloorCurrency, BIDDER_CURRENCY)) { final BigDecimal convertedFloor = currencyConversionService.convertCurrency( bidFloor, diff --git a/src/main/java/org/prebid/server/bidder/mgid/MgidBidder.java b/src/main/java/org/prebid/server/bidder/mgid/MgidBidder.java index 85a4c1dfc91..9da34c5e895 100644 --- a/src/main/java/org/prebid/server/bidder/mgid/MgidBidder.java +++ b/src/main/java/org/prebid/server/bidder/mgid/MgidBidder.java @@ -104,7 +104,7 @@ private static Imp modifyImp(Imp imp, ExtImpMgid impExt) throws PreBidException } private static String getCur(ExtImpMgid impMgid) { - return ObjectUtils.defaultIfNull( + return ObjectUtils.getIfNull( currencyValueOrNull(impMgid.getCurrency()), currencyValueOrNull(impMgid.getCur())); } @@ -113,7 +113,7 @@ private static String currencyValueOrNull(String value) { } private static BigDecimal getBidFloor(ExtImpMgid impMgid) { - return ObjectUtils.defaultIfNull( + return ObjectUtils.getIfNull( validBidFloorOrNull(impMgid.getBidfloor()), validBidFloorOrNull(impMgid.getBidFloorSecond())); } diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaAdRequest.java b/src/main/java/org/prebid/server/bidder/missena/MissenaAdRequest.java index 2f9722b2c82..f01c6a81e79 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaAdRequest.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaAdRequest.java @@ -2,10 +2,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Eid; import lombok.Builder; import lombok.Value; import java.math.BigDecimal; +import java.util.List; @Value @Builder(toBuilder = true) @@ -16,6 +18,11 @@ public class MissenaAdRequest { String currency; + Boolean debug; + + @JsonProperty("userEids") + List userEids; + BigDecimal floor; String floorCurrency; diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaAdResponse.java b/src/main/java/org/prebid/server/bidder/missena/MissenaAdResponse.java index 6a34c31efbf..acec2fa0199 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaAdResponse.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaAdResponse.java @@ -16,6 +16,10 @@ public class MissenaAdResponse { String currency; + Integer width; + + Integer height; + @JsonProperty("requestId") String requestId; } diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java index 4cfaa156e9b..1194d57444e 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java @@ -3,11 +3,14 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; +import com.iab.openrtb.request.Eid; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.Site; +import com.iab.openrtb.request.User; import com.iab.openrtb.response.Bid; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; @@ -21,6 +24,7 @@ import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.ExtUser; import org.prebid.server.proto.openrtb.ext.request.missena.ExtImpMissena; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; @@ -42,6 +46,9 @@ public class MissenaBidder implements Bidder { private static final String USD_CURRENCY = "USD"; private static final String EUR_CURRENCY = "EUR"; private static final String PUBLISHER_ID_MACRO = "PublisherID"; + private static final String VERSION_NAME = "prebid-server-java"; + private static final String VERSION_UNKNOWN = "unknown"; + private static final String VERSION_SEPARATOR = "@"; private final Uri endpointUrl; private final JacksonMapper mapper; @@ -91,22 +98,25 @@ private HttpRequest makeHttpRequest(BidRequest request, Imp im final Price floorInfo = resolveBidFloor(imp, request, requestCurrency); final MissenaUserParams userParams = MissenaUserParams.builder() + .apiKey(extImp.getApiKey()) .formats(extImp.getFormats()) .placement(extImp.getPlacement()) - .testMode(extImp.getTestMode()) + .sample(extImp.getSample()) .settings(extImp.getSettings()) .build(); final MissenaAdRequest missenaAdRequest = MissenaAdRequest.builder() .adUnit(imp.getId()) .currency(requestCurrency) + .debug(Objects.equals(request.getTest(), 1) ? Boolean.TRUE : null) + .userEids(resolveUserEids(request.getUser())) .floor(floorInfo.getValue()) .floorCurrency(floorInfo.getCurrency()) .idempotencyKey(request.getId()) .requestId(request.getId()) .timeout(request.getTmax()) .params(userParams) - .version(prebidVersionProvider.getNameVersionRecord()) + .version(resolveVersion()) .bidRequest(request) .build(); @@ -120,6 +130,17 @@ private HttpRequest makeHttpRequest(BidRequest request, Imp im .build(); } + private String resolveVersion() { + final String version = StringUtils.substringAfter(prebidVersionProvider.getNameVersionRecord(), "/"); + return VERSION_NAME + VERSION_SEPARATOR + (StringUtils.isNotEmpty(version) ? version : VERSION_UNKNOWN); + } + + private static List resolveUserEids(User user) { + final ExtUser extUser = user != null ? user.getExt() : null; + final List eids = extUser != null ? extUser.getEids() : null; + return CollectionUtils.isNotEmpty(eids) ? eids : null; + } + private Price resolveBidFloor(Imp imp, BidRequest bidRequest, String targetCurrency) { final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); return BidderUtil.isValidPrice(initialBidFloorPrice) @@ -202,6 +223,8 @@ private BidderBid extractBid(BidRequest request, MissenaAdResponse response) { .impid(request.getImp().getFirst().getId()) .adm(response.getAd()) .crid(response.getRequestId()) + .w(response.getWidth()) + .h(response.getHeight()) .build(); return BidderBid.of(bid, BidType.banner, response.getCurrency()); diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaUserParams.java b/src/main/java/org/prebid/server/bidder/missena/MissenaUserParams.java index e63a704a60c..bc97b9242bc 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaUserParams.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaUserParams.java @@ -1,7 +1,7 @@ package org.prebid.server.bidder.missena; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.node.ObjectNode; // Changed import +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Builder; import lombok.Value; @@ -11,13 +11,14 @@ @Value public class MissenaUserParams { + @JsonProperty("apiKey") + String apiKey; + List formats; String placement; - @JsonProperty("test") - String testMode; + String sample; ObjectNode settings; } - diff --git a/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java b/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java index 0e36d2b1411..a7342a2c82e 100644 --- a/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java +++ b/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java @@ -84,7 +84,7 @@ private Imp modifyImp(Imp firstImp, ExtImpMobkoi extImpMobkoi) { } throw new PreBidException("invalid because it comes with neither request.imp[0].tagId nor " - + "req.imp[0].ext.Bidder.placementId"); + + "req.imp[0].ext.Bidder.placementId"); } private static BidRequest modifyBidRequest(BidRequest bidRequest, Imp modifiedFirstImp) { diff --git a/src/main/java/org/prebid/server/bidder/msft/MsftBidder.java b/src/main/java/org/prebid/server/bidder/msft/MsftBidder.java index d3b960e9185..186b8be7602 100644 --- a/src/main/java/org/prebid/server/bidder/msft/MsftBidder.java +++ b/src/main/java/org/prebid/server/bidder/msft/MsftBidder.java @@ -17,6 +17,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.model.Endpoint; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.appnexus.SameValueValidator; @@ -80,7 +81,7 @@ public MsftBidder(String endpointUrl, this.endpointUrl = Uri.of(endpointUrl); this.hbSource = hbSource; this.hbSourceVideo = hbSourceVideo; - this.iabCategories = ObjectUtils.defaultIfNull(iabCategories, Collections.emptyMap()); + this.iabCategories = ObjectUtils.getIfNull(iabCategories, Collections.emptyMap()); this.mapper = Objects.requireNonNull(mapper); } @@ -170,7 +171,7 @@ private Banner updateBanner(Banner banner, ExtImpMsft extImp) { } return bannerBuilder - .api(ObjectUtils.defaultIfNull(banner.getApi(), extImp.getBannerFrameworks())) + .api(ObjectUtils.getIfNull(banner.getApi(), extImp.getBannerFrameworks())) .build(); } @@ -244,8 +245,8 @@ private JsonNode updateRequestExtMsft(ExtRequest requestExt, ExtRequestMsft requ final ExtRequestMsft.ExtRequestMsftBuilder updatedRequestExtMsftBuilder = Optional.ofNullable(requestExtMsft) .map(ExtRequestMsft::toBuilder) .orElseGet(ExtRequestMsft::builder) - .isAmp(BooleanUtils.toInteger(StringUtils.equals(endpointUrl, Endpoint.openrtb2_amp.value()))) - .hbSource(StringUtils.equals(endpointUrl, Endpoint.openrtb2_video.value()) ? hbSourceVideo : hbSource); + .isAmp(BooleanUtils.toInteger(Strings.CS.equals(endpointUrl, Endpoint.openrtb2_amp.value()))) + .hbSource(Strings.CS.equals(endpointUrl, Endpoint.openrtb2_video.value()) ? hbSourceVideo : hbSource); Optional.ofNullable(requestExt) .map(ExtRequest::getPrebid) diff --git a/src/main/java/org/prebid/server/bidder/nativery/NativeryBidder.java b/src/main/java/org/prebid/server/bidder/nativery/NativeryBidder.java index ef333e4d95c..f221539754f 100644 --- a/src/main/java/org/prebid/server/bidder/nativery/NativeryBidder.java +++ b/src/main/java/org/prebid/server/bidder/nativery/NativeryBidder.java @@ -11,6 +11,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.model.Endpoint; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; @@ -67,7 +68,7 @@ public Result>> makeHttpRequests(BidRequest request final List errors = new ArrayList<>(); final String requestEndpointName = extractEndpointName(request); - final boolean isAmp = StringUtils.equals(requestEndpointName, Endpoint.openrtb2_amp.value()); + final boolean isAmp = Strings.CS.equals(requestEndpointName, Endpoint.openrtb2_amp.value()); final List validImps = new ArrayList<>(); String widgetId = null; diff --git a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java index 4e6d9a21612..46b47fee40a 100644 --- a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java +++ b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java @@ -120,7 +120,7 @@ private static ExtBidPrebidVideo videoInfo(BidType bidType, Bid bid) { final Integer duration = bid.getDur(); return ExtBidPrebidVideo.of( - ObjectUtils.defaultIfNull(duration, 0), + ObjectUtils.getIfNull(duration, 0), CollectionUtils.isNotEmpty(cat) ? cat.getFirst() : StringUtils.EMPTY); } } diff --git a/src/main/java/org/prebid/server/bidder/orbidder/OrbidderBidder.java b/src/main/java/org/prebid/server/bidder/orbidder/OrbidderBidder.java index 4565c91ee28..7b0c099aefc 100644 --- a/src/main/java/org/prebid/server/bidder/orbidder/OrbidderBidder.java +++ b/src/main/java/org/prebid/server/bidder/orbidder/OrbidderBidder.java @@ -7,6 +7,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -72,7 +73,7 @@ public Result>> makeHttpRequests(BidRequest request private BigDecimal resolveBidFloor(BidRequest bidRequest, String bidfloorcur, BigDecimal bidfloor) { if (BidderUtil.isValidPrice(bidfloor) - && !StringUtils.equalsIgnoreCase(bidfloorcur, BIDDER_CURRENCY) + && !Strings.CI.equals(bidfloorcur, BIDDER_CURRENCY) && StringUtils.isNotBlank(bidfloorcur)) { return currencyConversionService.convertCurrency(bidfloor, bidRequest, bidfloorcur, BIDDER_CURRENCY); } diff --git a/src/main/java/org/prebid/server/bidder/playdigo/PlaydigoBidder.java b/src/main/java/org/prebid/server/bidder/playdigo/PlaydigoBidder.java index eec8b56f980..997b97ef5b4 100644 --- a/src/main/java/org/prebid/server/bidder/playdigo/PlaydigoBidder.java +++ b/src/main/java/org/prebid/server/bidder/playdigo/PlaydigoBidder.java @@ -134,7 +134,7 @@ private List extractBids(BidResponse bidResponse) { } private BidType getBidType(Bid bid) { - final Integer markupType = ObjectUtils.defaultIfNull(bid.getMtype(), 0); + final Integer markupType = ObjectUtils.getIfNull(bid.getMtype(), 0); return switch (markupType) { case 1 -> BidType.banner; diff --git a/src/main/java/org/prebid/server/bidder/preciso/PrecisoBidder.java b/src/main/java/org/prebid/server/bidder/preciso/PrecisoBidder.java index fffd1bcceaa..731275188cc 100644 --- a/src/main/java/org/prebid/server/bidder/preciso/PrecisoBidder.java +++ b/src/main/java/org/prebid/server/bidder/preciso/PrecisoBidder.java @@ -8,7 +8,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -38,8 +38,8 @@ public class PrecisoBidder implements Bidder { private static final TypeReference> PRECISO_EXT_TYPE_REFERENCE = - new TypeReference<>() { - }; + new TypeReference<>() { + }; private static final String BIDDER_CURRENCY = "USD"; private final String endpointUrl; @@ -130,28 +130,27 @@ private Price resolveBidFloor(Imp imp, ExtImpPreciso impExt, BidRequest bidReque ? brCur.getFirst() : null; final Price impExtBidFloorPrice = Price.of(impExtCurrency, impExtBidFloor); - final Price resolvedPrice = initialBidFloorPrice.getValue() == null ? impExtBidFloorPrice - : initialBidFloorPrice; + final Price resolvedPrice = initialBidFloorPrice.getValue() == null + ? impExtBidFloorPrice + : initialBidFloorPrice; return BidderUtil.isValidPrice(resolvedPrice) - && !StringUtils.equalsIgnoreCase(resolvedPrice.getCurrency(), BIDDER_CURRENCY) - ? convertBidFloor(resolvedPrice, imp.getId(), bidRequest) - : resolvedPrice; + && !Strings.CI.equals(resolvedPrice.getCurrency(), BIDDER_CURRENCY) + ? convertBidFloor(resolvedPrice, imp.getId(), bidRequest) + : resolvedPrice; } private Price convertBidFloor(Price bidFloorPrice, String impId, BidRequest bidRequest) { final String bidFloorCur = bidFloorPrice.getCurrency(); try { final BigDecimal convertedPrice = currencyConversionService - .convertCurrency(bidFloorPrice.getValue(), - bidRequest, bidFloorCur, BIDDER_CURRENCY); + .convertCurrency(bidFloorPrice.getValue(), bidRequest, bidFloorCur, BIDDER_CURRENCY); return Price.of(BIDDER_CURRENCY, convertedPrice); } catch (PreBidException e) { throw new PreBidException( - String.format( - "Unable to convert provided bid floor currency from %s to %s for imp `%s`", - bidFloorCur, BIDDER_CURRENCY, impId)); + "Unable to convert provided bid floor currency from %s to %s for imp `%s`" + .formatted(bidFloorCur, BIDDER_CURRENCY, impId)); } } @@ -163,6 +162,6 @@ private static BidType getBidType(Bid bid) { .map(BidType::fromString) .orElseThrow(() -> new PreBidException( "Missing ext.prebid.type in bid for impression : %s." - .formatted(bid.getImpid()))); + .formatted(bid.getImpid()))); } } diff --git a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java index 16c3f27e2f5..857f212a209 100644 --- a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java +++ b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java @@ -251,8 +251,8 @@ private static PubmaticWrapper merge(PubmaticWrapper left, PubmaticWrapper right } return PubmaticWrapper.of( - ObjectUtils.defaultIfNull(stripToNull(left.getProfile()), right.getProfile()), - ObjectUtils.defaultIfNull(stripToNull(left.getVersion()), right.getVersion())); + ObjectUtils.getIfNull(stripToNull(left.getProfile()), right.getProfile()), + ObjectUtils.getIfNull(stripToNull(left.getVersion()), right.getVersion())); } private static boolean isWrapperValid(PubmaticWrapper wrapper) { diff --git a/src/main/java/org/prebid/server/bidder/pubnative/PubnativeBidder.java b/src/main/java/org/prebid/server/bidder/pubnative/PubnativeBidder.java index 3d89b044405..2fb2768c73b 100644 --- a/src/main/java/org/prebid/server/bidder/pubnative/PubnativeBidder.java +++ b/src/main/java/org/prebid/server/bidder/pubnative/PubnativeBidder.java @@ -13,6 +13,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -106,8 +107,8 @@ private Imp resolveImp(BidRequest bidRequest, Imp imp) { return resolvedBanner == null && resolvedBidFloor == null ? imp : imp.toBuilder() - .banner(ObjectUtils.defaultIfNull(resolvedBanner, imp.getBanner())) - .bidfloor(ObjectUtils.defaultIfNull(resolvedBidFloor, imp.getBidfloor())) + .banner(ObjectUtils.getIfNull(resolvedBanner, imp.getBanner())) + .bidfloor(ObjectUtils.getIfNull(resolvedBidFloor, imp.getBidfloor())) .bidfloorcur(resolvedBidFloor == null ? imp.getBidfloorcur() : PUBNATIVE_CURRENCY) .build(); } @@ -136,7 +137,7 @@ private BigDecimal resolveBidFloor(BidRequest bidRequest, Imp imp) { final BigDecimal bidFloor = imp.getBidfloor(); final String bidFloorCur = resolveBidFloorCurrency(bidRequest, imp.getBidfloorcur()); if (!BidderUtil.isValidPrice(bidFloor) - || StringUtils.equals(bidFloorCur, PUBNATIVE_CURRENCY) + || Strings.CS.equals(bidFloorCur, PUBNATIVE_CURRENCY) || StringUtils.isEmpty(bidFloorCur)) { return null; } diff --git a/src/main/java/org/prebid/server/bidder/readpeak/ReadPeakBidder.java b/src/main/java/org/prebid/server/bidder/readpeak/ReadPeakBidder.java index a24cbf044c6..334faa4b5ee 100644 --- a/src/main/java/org/prebid/server/bidder/readpeak/ReadPeakBidder.java +++ b/src/main/java/org/prebid/server/bidder/readpeak/ReadPeakBidder.java @@ -12,6 +12,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -174,14 +175,14 @@ private static Bid resolveMacros(Bid bid) { final String priceAsString = price != null ? price.toPlainString() : "0"; return bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) - .burl(StringUtils.replace(bid.getBurl(), PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .burl(Strings.CS.replace(bid.getBurl(), PRICE_MACRO, priceAsString)) .build(); } private static BidType getBidType(Bid bid) { - final Integer markupType = ObjectUtils.defaultIfNull(bid.getMtype(), 0); + final Integer markupType = ObjectUtils.getIfNull(bid.getMtype(), 0); return switch (markupType) { case 1 -> BidType.banner; diff --git a/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java b/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java index 8d45320cb9c..be9f76a155c 100644 --- a/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java +++ b/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.App; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.Publisher; @@ -13,6 +14,7 @@ import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -88,6 +90,7 @@ public Result>> makeHttpRequests(BidRequest bidRequ final BidRequest outgoingRequest = bidRequest.toBuilder() .cur(Collections.singletonList(BIDDER_CURRENCY)) .site(modifySite(bidRequest.getSite(), publisherId)) + .app(modifyApp(bidRequest.getApp(), publisherId)) .imp(modifiedImps) .build(); @@ -114,7 +117,7 @@ private Price resolveBidFloor(Imp imp, ExtImpRtbhouse impExt, BidRequest bidRequ ? impExtBidFloorPrice : initialBidFloorPrice; return BidderUtil.isValidPrice(resolvedPrice) - && !StringUtils.equalsIgnoreCase(resolvedPrice.getCurrency(), BIDDER_CURRENCY) + && !Strings.CI.equals(resolvedPrice.getCurrency(), BIDDER_CURRENCY) ? convertBidFloor(resolvedPrice, imp.getId(), bidRequest) : resolvedPrice; } @@ -178,24 +181,33 @@ private static Optional extractPbadslot(Imp imp) { } private Site modifySite(Site site, String publisherId) { + return Optional.ofNullable(site) + .map(Site::toBuilder) + .map(builder -> builder.publisher(modifyPublisher(site.getPublisher(), publisherId))) + .map(Site.SiteBuilder::build) + .orElse(site); + } + + private App modifyApp(App app, String publisherId) { + return Optional.ofNullable(app) + .map(App::toBuilder) + .map(builder -> builder.publisher(modifyPublisher(app.getPublisher(), publisherId))) + .map(App.AppBuilder::build) + .orElse(app); + } + + private Publisher modifyPublisher(Publisher publisher, String publisherId) { final ObjectNode prebidNode = mapper.mapper().createObjectNode(); prebidNode.put("publisherId", publisherId); final ExtPublisher extPublisher = ExtPublisher.empty(); extPublisher.addProperty("prebid", prebidNode); - final Publisher publisher = Optional.ofNullable(site) - .map(Site::getPublisher) + return Optional.ofNullable(publisher) .map(Publisher::toBuilder) .orElseGet(Publisher::builder) .ext(extPublisher) .build(); - - return Optional.ofNullable(site) - .map(Site::toBuilder) - .orElseGet(Site::builder) - .publisher(publisher) - .build(); } @Override @@ -285,8 +297,8 @@ private static Bid resolveMacros(Bid bid) { final String priceAsString = price != null ? price.toPlainString() : "0"; return bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) .build(); } } diff --git a/src/main/java/org/prebid/server/bidder/scalibur/ScaliburBidder.java b/src/main/java/org/prebid/server/bidder/scalibur/ScaliburBidder.java new file mode 100644 index 00000000000..f6ae3d0bee7 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/scalibur/ScaliburBidder.java @@ -0,0 +1,319 @@ +package org.prebid.server.bidder.scalibur; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.IntNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.Video; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.prebid.server.bidder.Bidder; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.Price; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.json.DecodeException; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.ExtRequest; +import org.prebid.server.proto.openrtb.ext.request.scalibur.ExtImpScalibur; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.BidderUtil; +import org.prebid.server.util.Uri; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class ScaliburBidder implements Bidder { + + private static final TypeReference> TYPE_REFERENCE = new TypeReference<>() { + }; + private static final String DEFAULT_HOST_LABEL = "srv"; + private static final String HOST_MACRO = "Host"; + private static final String DEFAULT_BID_CURRENCY = "USD"; + private static final String VAST_XML = """ + + """; + + private final Uri endpointUrl; + private final CurrencyConversionService currencyConversionService; + private final JacksonMapper mapper; + + public ScaliburBidder(String endpointUrl, + CurrencyConversionService currencyConversionService, + JacksonMapper mapper) { + + this.endpointUrl = Uri.of(endpointUrl); + this.currencyConversionService = Objects.requireNonNull(currencyConversionService); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public Result>> makeHttpRequests(BidRequest bidRequest) { + final List errors = new ArrayList<>(); + final Map> hostLabelToImps = new HashMap<>(); + final List> httpRequests = new ArrayList<>(); + + for (Imp imp : bidRequest.getImp()) { + try { + final ExtImpScalibur scaliburExt = parseImpExt(imp); + final String hostLabel = StringUtils.defaultIfEmpty(scaliburExt.getHost(), DEFAULT_HOST_LABEL); + final Imp modifiedImp = modifyImp(imp, scaliburExt, bidRequest); + + hostLabelToImps.computeIfAbsent(hostLabel, ignored -> new ArrayList<>()).add(modifiedImp); + } catch (PreBidException e) { + errors.add(BidderError.badInput(e.getMessage())); + } + } + + if (hostLabelToImps.isEmpty()) { + return Result.withErrors(errors); + } + + for (Map.Entry> entry : hostLabelToImps.entrySet()) { + final BidRequest modifiedBidRequest = bidRequest.toBuilder() + .imp(entry.getValue()) + .cur(null) + .ext(isDebugEnabled(bidRequest) ? createDebugExt() : null) + .build(); + httpRequests.add(BidderUtil.defaultRequest( + modifiedBidRequest, + resolveUrl(endpointUrl, entry.getKey()), + mapper)); + } + + return Result.of(httpRequests, errors); + } + + private ExtImpScalibur parseImpExt(Imp imp) { + try { + return mapper.mapper().convertValue(imp.getExt(), TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException(e.getMessage()); + } + } + + private Imp modifyImp(Imp imp, + ExtImpScalibur extImpScalibur, + BidRequest bidRequest) { + + final String tagId = StringUtils.defaultIfEmpty(imp.getTagid(), extImpScalibur.getPlacementId()); + + if (StringUtils.isBlank(tagId)) { + throw new PreBidException("imp %s: missing placement; set imp.tagid or the placementId param" + .formatted(imp.getId())); + } + + final Price resolvedBidFloor = resolveBidFloor(imp, extImpScalibur, bidRequest); + + return imp.toBuilder() + .tagid(tagId) + .bidfloor(resolvedBidFloor.getValue()) + .bidfloorcur(resolvedBidFloor.getCurrency()) + .video(resolveVideo(imp.getVideo())) + .ext(resolveImpExt(resolvedBidFloor, imp.getExt())) + .build(); + } + + private Price resolveBidFloor(Imp imp, + ExtImpScalibur extImpScalibur, + BidRequest bidRequest) { + + final BigDecimal extPrice = extImpScalibur.getBidFloor(); + final Price price = BidderUtil.isValidPrice(extPrice) + ? Price.of(StringUtils.defaultIfBlank(extImpScalibur.getBidFloorCur(), imp.getBidfloorcur()), extPrice) + : Price.of(imp.getBidfloorcur(), imp.getBidfloor()); + if (BidderUtil.shouldConvertBidFloor(price, DEFAULT_BID_CURRENCY)) { + return convertBidFloor(price, bidRequest); + } + return Price.of( + StringUtils.defaultIfBlank(price.getCurrency(), DEFAULT_BID_CURRENCY), + price.getValue()); + } + + private Price convertBidFloor(Price bidFloorPrice, BidRequest bidRequest) { + final BigDecimal convertedPrice = currencyConversionService.convertCurrency(bidFloorPrice.getValue(), + bidRequest, + bidFloorPrice.getCurrency(), + DEFAULT_BID_CURRENCY); + + return Price.of(DEFAULT_BID_CURRENCY, convertedPrice); + } + + private ObjectNode resolveImpExt(Price bidFloor, ObjectNode impExt) { + final ObjectNode ext = impExt.get("bidder").deepCopy(); + ext.remove("placementId"); + ext.remove("host"); + if (BidderUtil.isValidPrice(bidFloor)) { + ext.put("bidfloor", bidFloor.getValue()); + ext.put("bidfloorcur", bidFloor.getCurrency()); + } else { + ext.remove("bidfloor"); + ext.remove("bidfloorcur"); + } + final JsonNode gpidNode = impExt.get("gpid"); + if (gpidNode != null && !gpidNode.isNull()) { + ext.set("gpid", gpidNode); + } + return ext; + } + + private Video resolveVideo(Video video) { + if (video == null) { + return null; + } + + final Video.VideoBuilder builder = video.toBuilder(); + + if (CollectionUtils.isEmpty(video.getMimes())) { + builder.mimes(Collections.singletonList("video/mp4")); + } + if (BidderUtil.isNullOrZero(video.getMinduration())) { + builder.minduration(1); + } + if (BidderUtil.isNullOrZero(video.getMaxduration())) { + builder.maxduration(180); + } + if (BidderUtil.isNullOrZero(video.getMaxbitrate())) { + builder.maxbitrate(30_000); + } + if (CollectionUtils.isEmpty(video.getProtocols())) { + builder.protocols(List.of(2, 3, 5, 6)); + } + if (BidderUtil.isNullOrZero(video.getW())) { + builder.w(640); + } + if (BidderUtil.isNullOrZero(video.getH())) { + builder.h(480); + } + if (BidderUtil.isNullOrZero(video.getPlacement())) { + builder.placement(1); + } + if (BidderUtil.isNullOrZero(video.getLinearity())) { + builder.linearity(1); + } + + return builder.build(); + } + + private boolean isDebugEnabled(BidRequest bidRequest) { + if (Objects.equals(bidRequest.getTest(), 1)) { + return true; + } + final ExtRequest ext = bidRequest.getExt(); + if (ext == null || ext.getPrebid() == null) { + return false; + } + return Objects.equals(ext.getPrebid().getDebug(), 1); + } + + private ExtRequest createDebugExt() { + final ExtRequest extRequest = ExtRequest.empty(); + extRequest.addProperty("isDebug", IntNode.valueOf(1)); + return extRequest; + } + + private String resolveUrl(Uri configEndpoint, String externalUrl) { + return configEndpoint.replaceMacro(HOST_MACRO, externalUrl).expand(); + } + + @Override + public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + try { + final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + return extractBids(httpCall.getRequest().getPayload(), bidResponse); + } catch (DecodeException | PreBidException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + } + + private Result> extractBids(BidRequest bidRequest, BidResponse bidResponse) { + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Result.empty(); + } + final List errors = new ArrayList<>(); + final List bidderBids = new ArrayList<>(); + for (SeatBid seatBid : bidResponse.getSeatbid()) { + if (CollectionUtils.isEmpty(seatBid.getBid())) { + continue; + } + + for (Bid bid : seatBid.getBid()) { + try { + bidderBids.add(createBidderBid(bid, bidRequest, bidResponse)); + } catch (PreBidException e) { + errors.add(BidderError.badServerResponse(e.getMessage())); + } + } + } + + return Result.of(bidderBids, errors); + } + + private BidderBid createBidderBid(Bid bid, BidRequest bidRequest, BidResponse bidResponse) { + final Imp imp = bidRequest.getImp().stream() + .filter(candidate -> Objects.equals(candidate.getId(), bid.getImpid())) + .findFirst() + .orElseThrow(() -> new PreBidException("Invalid bid imp ID %s".formatted(bid.getImpid()))); + + final BidType bidType = resolveBidType(bid, imp); + final Bid resolvedBid = bidType == BidType.video ? resolveVideoBid(bid) : bid; + final String resolvedCurrency = StringUtils.defaultIfEmpty(bidResponse.getCur(), DEFAULT_BID_CURRENCY); + + return BidderBid.of(resolvedBid, bidType, resolvedCurrency); + } + + private Bid resolveVideoBid(Bid bid) { + if (bid.getExt() == null) { + return bid; + } + + final JsonNode vastXml = bid.getExt().get("vastXml"); + if (isNonEmptyText(vastXml)) { + return bid.toBuilder().adm(vastXml.asText()).build(); + } + + final JsonNode vastUrl = bid.getExt().get("vastUrl"); + if (isNonEmptyText(vastUrl) && StringUtils.isEmpty(bid.getAdm())) { + return bid.toBuilder() + .adm(VAST_XML.formatted(vastUrl.asText()).trim()) + .build(); + } + return bid; + } + + private boolean isNonEmptyText(JsonNode node) { + return node != null && node.isTextual() && StringUtils.isNotEmpty(node.asText()); + } + + private BidType resolveBidType(Bid bid, Imp imp) { + if (Objects.equals(bid.getMtype(), 1)) { + return BidType.banner; + } + if (Objects.equals(bid.getMtype(), 2)) { + return BidType.video; + } + if (imp.getBanner() != null && imp.getVideo() == null) { + return BidType.banner; + } + if (imp.getVideo() != null && imp.getBanner() == null) { + return BidType.video; + } + throw new PreBidException( + "Unsupported or ambiguous media type for bid id=%s".formatted(bid.getId())); + } +} diff --git a/src/main/java/org/prebid/server/bidder/seedtag/SeedtagBidder.java b/src/main/java/org/prebid/server/bidder/seedtag/SeedtagBidder.java index 389fb88b147..97b02a18976 100644 --- a/src/main/java/org/prebid/server/bidder/seedtag/SeedtagBidder.java +++ b/src/main/java/org/prebid/server/bidder/seedtag/SeedtagBidder.java @@ -68,7 +68,7 @@ public Result>> makeHttpRequests(BidRequest request } } - if (modifiedImps.size() < 1) { + if (modifiedImps.isEmpty()) { return Result.withErrors(errors); } @@ -114,11 +114,11 @@ private static Imp modifyImp(Imp imp, Price bidFloorPrice) { private Price resolveBidFloor(Imp imp, BidRequest bidRequest) { final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); return BidderUtil.shouldConvertBidFloor(initialBidFloorPrice, BIDDER_CURRENCY) - ? convertBidFloor(initialBidFloorPrice, imp.getId(), bidRequest) + ? convertBidFloor(initialBidFloorPrice, bidRequest) : initialBidFloorPrice; } - private Price convertBidFloor(Price bidFloorPrice, String impId, BidRequest bidRequest) { + private Price convertBidFloor(Price bidFloorPrice, BidRequest bidRequest) { final BigDecimal convertedPrice = currencyConversionService.convertCurrency( bidFloorPrice.getValue(), bidRequest, diff --git a/src/main/java/org/prebid/server/bidder/sevio/SevioBidder.java b/src/main/java/org/prebid/server/bidder/sevio/SevioBidder.java new file mode 100644 index 00000000000..434ba516aeb --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/sevio/SevioBidder.java @@ -0,0 +1,96 @@ +package org.prebid.server.bidder.sevio; + +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import io.vertx.core.MultiMap; +import org.apache.commons.collections4.CollectionUtils; +import org.prebid.server.bidder.Bidder; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.json.DecodeException; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.BidderUtil; +import org.prebid.server.util.HttpUtil; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class SevioBidder implements Bidder { + + private final String endpointUrl; + private final JacksonMapper mapper; + + public SevioBidder(String endpointUrl, JacksonMapper mapper) { + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public Result>> makeHttpRequests(BidRequest bidRequest) { + final MultiMap headers = HttpUtil.headers().add(HttpUtil.X_OPENRTB_VERSION_HEADER, "2.6"); + return Result.withValue(BidderUtil.defaultRequest(bidRequest, headers, endpointUrl, mapper)); + } + + @Override + public final Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + try { + final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + final List errors = new ArrayList<>(); + return Result.of(extractBids(bidResponse, errors), errors); + } catch (DecodeException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + } + + private static List extractBids(BidResponse bidResponse, List errors) { + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Collections.emptyList(); + } + return bidsFromResponse(bidResponse, errors); + } + + private static List bidsFromResponse(BidResponse bidResponse, List errors) { + return bidResponse.getSeatbid().stream() + .filter(Objects::nonNull) + .map(SeatBid::getBid) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .map(bid -> makeBid(bid, bidResponse.getCur(), errors)) + .filter(Objects::nonNull) + .toList(); + } + + private static BidderBid makeBid(Bid bid, String currency, List errors) { + try { + return BidderBid.of(bid, getBidType(bid), currency); + } catch (PreBidException e) { + errors.add(BidderError.badServerResponse(e.getMessage())); + return null; + } + } + + private static BidType getBidType(Bid bid) { + final Integer mtype = bid.getMtype(); + if (mtype == null) { + throw new PreBidException("Missing MType for bid: " + bid.getId()); + } + + return switch (mtype) { + case 1 -> BidType.banner; + case 4 -> BidType.xNative; + default -> throw new PreBidException( + "failed to parse bid mtype (%d) for impression id \"%s\"".formatted(mtype, bid.getImpid())); + }; + } +} diff --git a/src/main/java/org/prebid/server/bidder/sharethrough/SharethroughBidder.java b/src/main/java/org/prebid/server/bidder/sharethrough/SharethroughBidder.java index 7fbb077bdc3..dd9faea2bc9 100644 --- a/src/main/java/org/prebid/server/bidder/sharethrough/SharethroughBidder.java +++ b/src/main/java/org/prebid/server/bidder/sharethrough/SharethroughBidder.java @@ -178,8 +178,8 @@ private static List union(List first, List second) { private Source modifySource(Source source) { return source != null ? source.toBuilder() - .ext(ObjectUtil.getIfNotNullOrDefault(source.getExt(), this::modifyExtSource, this::createExtSource)) - .build() + .ext(ObjectUtil.getIfNotNullOrDefault(source.getExt(), this::modifyExtSource, this::createExtSource)) + .build() : Source.builder().ext(createExtSource()).build(); } diff --git a/src/main/java/org/prebid/server/bidder/showheroes/ShowheroesBidder.java b/src/main/java/org/prebid/server/bidder/showheroes/ShowheroesBidder.java index b212950f322..ab484a5d3ec 100644 --- a/src/main/java/org/prebid/server/bidder/showheroes/ShowheroesBidder.java +++ b/src/main/java/org/prebid/server/bidder/showheroes/ShowheroesBidder.java @@ -12,7 +12,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -148,7 +148,7 @@ private ObjectNode modifyImpExt(ObjectNode impExt, ExtImpShowheroes shImpExt) { private static boolean shouldConvertFloor(Imp imp) { return BidderUtil.isValidPrice(imp.getBidfloor()) - && !StringUtils.equalsIgnoreCase(imp.getBidfloorcur(), BID_CURRENCY); + && !Strings.CI.equals(imp.getBidfloorcur(), BID_CURRENCY); } private BigDecimal resolveBidFloor(BidRequest bidRequest, Imp imp) { @@ -211,7 +211,6 @@ private List extractBids(BidResponse bidResponse) { private static BidType getBidType(Bid bid) { return switch (bid.getMtype()) { case 1 -> BidType.banner; - case 2 -> BidType.video; case null, default -> BidType.video; }; } diff --git a/src/main/java/org/prebid/server/bidder/silvermob/SilvermobBidder.java b/src/main/java/org/prebid/server/bidder/silvermob/SilvermobBidder.java index 19cd845a108..2820319147f 100644 --- a/src/main/java/org/prebid/server/bidder/silvermob/SilvermobBidder.java +++ b/src/main/java/org/prebid/server/bidder/silvermob/SilvermobBidder.java @@ -11,6 +11,7 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -100,7 +101,7 @@ private ExtImpSilvermob parseImpExt(Imp imp) { } private static Boolean isInvalidHost(String host) { - return !StringUtils.equalsAny(host, "eu", "us", "apac", "global"); + return !Strings.CS.equalsAny(host, "eu", "us", "apac", "global"); } private String resolveEndpoint(ExtImpSilvermob extImp) { diff --git a/src/main/java/org/prebid/server/bidder/silverpush/SilverPushDeviceTypeResolver.java b/src/main/java/org/prebid/server/bidder/silverpush/SilverPushDeviceTypeResolver.java index 576e344bbae..acd77f46f77 100644 --- a/src/main/java/org/prebid/server/bidder/silverpush/SilverPushDeviceTypeResolver.java +++ b/src/main/java/org/prebid/server/bidder/silverpush/SilverPushDeviceTypeResolver.java @@ -1,6 +1,6 @@ package org.prebid.server.bidder.silverpush; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import java.util.regex.Pattern; @@ -17,15 +17,15 @@ private SilverPushDeviceTypeResolver() { Pattern.CASE_INSENSITIVE); public static String resolveOs(String userAgent) { - if (StringUtils.containsIgnoreCase(userAgent, "Windows")) { + if (Strings.CI.contains(userAgent, "Windows")) { return "Windows"; - } else if (StringUtils.containsAnyIgnoreCase(userAgent, "iPhone", "iPod", "iPad")) { + } else if (Strings.CI.containsAny(userAgent, "iPhone", "iPod", "iPad")) { return "iOS"; - } else if (StringUtils.containsIgnoreCase(userAgent, "Mac OS X")) { + } else if (Strings.CI.contains(userAgent, "Mac OS X")) { return "macOS"; - } else if (StringUtils.containsIgnoreCase(userAgent, "Android")) { + } else if (Strings.CI.contains(userAgent, "Android")) { return "Android"; - } else if (StringUtils.containsIgnoreCase(userAgent, "Linux")) { + } else if (Strings.CI.contains(userAgent, "Linux")) { return "Linux"; } diff --git a/src/main/java/org/prebid/server/bidder/smaato/SmaatoBidder.java b/src/main/java/org/prebid/server/bidder/smaato/SmaatoBidder.java index 874c116c0d3..034ed6eddcd 100644 --- a/src/main/java/org/prebid/server/bidder/smaato/SmaatoBidder.java +++ b/src/main/java/org/prebid/server/bidder/smaato/SmaatoBidder.java @@ -20,6 +20,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.model.Endpoint; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; @@ -168,7 +169,7 @@ private static boolean isVideoRequest(BidRequest bidRequest) { final ExtRequestPrebidServer server = getIfNotNull(prebid, ExtRequestPrebid::getServer); final String endpointName = getIfNotNull(server, ExtRequestPrebidServer::getEndpoint); - return StringUtils.equals(endpointName, Endpoint.openrtb2_video.value()); + return Strings.CS.equals(endpointName, Endpoint.openrtb2_video.value()); } private List> constructPodRequests(BidRequest bidRequest, List errors) { diff --git a/src/main/java/org/prebid/server/bidder/sonobi/SonobiBidder.java b/src/main/java/org/prebid/server/bidder/sonobi/SonobiBidder.java index 7185d339495..51ba794f3f0 100644 --- a/src/main/java/org/prebid/server/bidder/sonobi/SonobiBidder.java +++ b/src/main/java/org/prebid/server/bidder/sonobi/SonobiBidder.java @@ -7,6 +7,7 @@ import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -93,7 +94,7 @@ private Price resolveBidFloor(BidRequest bidRequest, Imp imp) { if (BidderUtil.isValidPrice(bidFloor) && StringUtils.isNotBlank(bidFloorCurrency) - && !StringUtils.equalsIgnoreCase(bidFloorCurrency, BIDDER_CURRENCY)) { + && !Strings.CI.equals(bidFloorCurrency, BIDDER_CURRENCY)) { return Price.of( BIDDER_CURRENCY, currencyConversionService.convertCurrency(bidFloor, bidRequest, bidFloorCurrency, BIDDER_CURRENCY)); diff --git a/src/main/java/org/prebid/server/bidder/sovrn/SovrnBidder.java b/src/main/java/org/prebid/server/bidder/sovrn/SovrnBidder.java index ee79f854777..568e52a5c6a 100644 --- a/src/main/java/org/prebid/server/bidder/sovrn/SovrnBidder.java +++ b/src/main/java/org/prebid/server/bidder/sovrn/SovrnBidder.java @@ -108,7 +108,7 @@ private static BigDecimal resolveBidFloor(BigDecimal impBidFloor, BigDecimal ext } private String resolveTagId(ExtImpSovrn sovrnExt) { - final String tagId = ObjectUtils.defaultIfNull(sovrnExt.getTagid(), sovrnExt.getLegacyTagId()); + final String tagId = ObjectUtils.getIfNull(sovrnExt.getTagid(), sovrnExt.getLegacyTagId()); if (StringUtils.isEmpty(tagId)) { throw new PreBidException("Missing required parameter 'tagid'"); } diff --git a/src/main/java/org/prebid/server/bidder/sparteo/SparteoBidder.java b/src/main/java/org/prebid/server/bidder/sparteo/SparteoBidder.java index ab02a7e380b..a6d79592506 100644 --- a/src/main/java/org/prebid/server/bidder/sparteo/SparteoBidder.java +++ b/src/main/java/org/prebid/server/bidder/sparteo/SparteoBidder.java @@ -112,7 +112,7 @@ private static ObjectNode modifyImpExt(Imp imp) { private Site modifySite(Site site, String networkId) { if (site == null) { - return site; + return null; } final Publisher originalPublisher = site.getPublisher() != null @@ -126,7 +126,7 @@ private Site modifySite(Site site, String networkId) { private App modifyApp(App app, String networkId) { if (app == null) { - return app; + return null; } final Publisher originalPublisher = app.getPublisher() != null diff --git a/src/main/java/org/prebid/server/bidder/sparteo/util/SparteoUtil.java b/src/main/java/org/prebid/server/bidder/sparteo/util/SparteoUtil.java index bcb098f687d..0f85e9f721b 100644 --- a/src/main/java/org/prebid/server/bidder/sparteo/util/SparteoUtil.java +++ b/src/main/java/org/prebid/server/bidder/sparteo/util/SparteoUtil.java @@ -1,6 +1,7 @@ package org.prebid.server.bidder.sparteo.util; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import java.net.URI; import java.net.URISyntaxException; @@ -19,7 +20,7 @@ public static String normalizeHostname(String host) { String hostname = null; try { hostname = new URI(h).getHost(); - } catch (URISyntaxException e) { + } catch (URISyntaxException _) { } if (StringUtils.isNotEmpty(hostname)) { @@ -33,8 +34,8 @@ public static String normalizeHostname(String host) { } h = h.toLowerCase(); - h = StringUtils.removeStart(h, "www."); - h = StringUtils.removeEnd(h, "."); + h = Strings.CS.removeStart(h, "www."); + h = Strings.CS.removeEnd(h, "."); return "null".equals(h) ? "" : h; } diff --git a/src/main/java/org/prebid/server/bidder/synapsehx/SynapseHXBidder.java b/src/main/java/org/prebid/server/bidder/synapsehx/SynapseHXBidder.java new file mode 100644 index 00000000000..3f232210cf7 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/synapsehx/SynapseHXBidder.java @@ -0,0 +1,160 @@ +package org.prebid.server.bidder.synapsehx; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import io.vertx.core.MultiMap; +import org.apache.commons.collections4.CollectionUtils; +import org.prebid.server.bidder.Bidder; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.json.DecodeException; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.synapsehx.ExtImpSynapseHX; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; +import org.prebid.server.util.BidderUtil; +import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.Uri; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class SynapseHXBidder implements Bidder { + + private static final TypeReference> SYNAPSE_HX_EXT_TYPE_REFERENCE = + new TypeReference<>() { + }; + + private static final TypeReference> EXT_PREBID_TYPE_REFERENCE = + new TypeReference<>() { + }; + + private static final String OPENRTB_VERSION = "2.6"; + + private final Uri endpoint; + private final JacksonMapper mapper; + + public SynapseHXBidder(String endpoint, JacksonMapper mapper) { + this.endpoint = Uri.of(endpoint); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public final Result>> makeHttpRequests(BidRequest bidRequest) { + final Imp firstImp = bidRequest.getImp().getFirst(); + final String uri; + + try { + uri = makeUri(getTenantId(firstImp)); + } catch (PreBidException e) { + return Result.withError(BidderError.badInput(e.getMessage())); + } + + final MultiMap headers = HttpUtil.headers(); + headers.add(HttpUtil.X_OPENRTB_VERSION_HEADER, OPENRTB_VERSION); + + return Result.withValue(BidderUtil.defaultRequest(bidRequest, headers, uri, mapper)); + } + + private String getTenantId(Imp firstImp) { + try { + return mapper.mapper() + .convertValue(firstImp.getExt(), SYNAPSE_HX_EXT_TYPE_REFERENCE) + .getBidder() + .getTenantId(); + } catch (IllegalArgumentException e) { + throw new PreBidException("Failed to parse bidder parameters: %s".formatted(e.getMessage())); + } + } + + private String makeUri(String tenantId) { + return endpoint.addQueryParam("pid", tenantId).expand(); + } + + @Override + public final Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + try { + final List bidderErrors = new ArrayList<>(); + final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + return Result.of(extractBids(bidResponse, bidderErrors), bidderErrors); + } catch (DecodeException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + } + + private List extractBids(BidResponse bidResponse, List bidderErrors) { + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Collections.emptyList(); + } + return bidsFromResponse(bidResponse, bidderErrors); + } + + private List bidsFromResponse(BidResponse bidResponse, List bidderErrors) { + return bidResponse.getSeatbid().stream() + .filter(Objects::nonNull) + .map(SeatBid::getBid) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .map(bid -> makeBidderBid(bid, bidResponse, bidderErrors)) + .filter(Objects::nonNull) + .toList(); + } + + private BidderBid makeBidderBid(Bid bid, BidResponse bidResponse, List bidderErrors) { + final BidType bidType = getBidType(bid, bidderErrors); + return bidType == null + ? null + : BidderBid.of(bid, bidType, bidResponse.getCur()); + } + + private BidType getBidType(Bid bid, List errors) { + final Integer mType = bid.getMtype(); + return mType != null + ? getBidTypeFromMType(mType, errors) + : getBidTypeFromExt(bid.getExt(), errors); + } + + private static BidType getBidTypeFromMType(Integer mType, List errors) { + return switch (mType) { + case 1 -> BidType.banner; + case 2 -> BidType.video; + default -> { + errors.add(BidderError.badServerResponse("Unsupported media type: %d".formatted(mType))); + yield null; + } + }; + } + + private BidType getBidTypeFromExt(ObjectNode bidExt, List errors) { + final BidType bidType = Optional.ofNullable(bidExt) + .map(ext -> mapper.mapper().convertValue(ext, EXT_PREBID_TYPE_REFERENCE)) + .map(ExtPrebid::getPrebid) + .map(ExtBidPrebid::getType) + .orElse(null); + + return switch (bidType) { + case banner -> BidType.banner; + case video -> BidType.video; + case null, default -> { + errors.add(BidderError.badServerResponse("Unsupported media type: %s".formatted(bidType))); + yield null; + } + }; + } + +} diff --git a/src/main/java/org/prebid/server/bidder/taboola/TaboolaBidder.java b/src/main/java/org/prebid/server/bidder/taboola/TaboolaBidder.java index 003665ecbea..d9589d18744 100644 --- a/src/main/java/org/prebid/server/bidder/taboola/TaboolaBidder.java +++ b/src/main/java/org/prebid/server/bidder/taboola/TaboolaBidder.java @@ -13,6 +13,7 @@ import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -293,8 +294,8 @@ private static Bid resolveMacros(Bid bid) { final String priceAsString = price != null ? price.toPlainString() : "0"; return bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) .build(); } } diff --git a/src/main/java/org/prebid/server/bidder/teal/TealBidder.java b/src/main/java/org/prebid/server/bidder/teal/TealBidder.java index 2c56e23ff2e..56b51a13f31 100644 --- a/src/main/java/org/prebid/server/bidder/teal/TealBidder.java +++ b/src/main/java/org/prebid/server/bidder/teal/TealBidder.java @@ -119,7 +119,7 @@ private static ObjectNode getOrCreate(ObjectNode parent, String field) { } private BidRequest modifyBidRequest(BidRequest request, String account, List modifiedImps) { - final ExtRequest ext = ObjectUtils.defaultIfNull(request.getExt(), ExtRequest.empty()); + final ExtRequest ext = ObjectUtils.getIfNull(request.getExt(), ExtRequest.empty()); ext.addProperty("bids", mapper.mapper().createObjectNode().put("pbs", 1)); return request.toBuilder() @@ -133,16 +133,16 @@ private BidRequest modifyBidRequest(BidRequest request, String account, List errors) { return switch (bid.getMtype()) { case 1 -> BidType.banner; case 2 -> BidType.video; + case 3 -> BidType.audio; case 4 -> BidType.xNative; case null, default -> { errors.add(BidderError.badServerResponse( @@ -229,9 +231,9 @@ private static Bid resolvePriceMacros(Bid bid) { final String priceAsString = price != null ? price.toPlainString() : "0"; return bid.toBuilder() - .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) - .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) - .burl(StringUtils.replace(bid.getBurl(), PRICE_MACRO, priceAsString)) + .nurl(Strings.CS.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) + .adm(Strings.CS.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .burl(Strings.CS.replace(bid.getBurl(), PRICE_MACRO, priceAsString)) .build(); } } diff --git a/src/main/java/org/prebid/server/bidder/tradplus/TradPlusBidder.java b/src/main/java/org/prebid/server/bidder/tradplus/TradPlusBidder.java index 66a3fe86367..86ce66d393b 100644 --- a/src/main/java/org/prebid/server/bidder/tradplus/TradPlusBidder.java +++ b/src/main/java/org/prebid/server/bidder/tradplus/TradPlusBidder.java @@ -109,8 +109,9 @@ public Result> makeBids(BidderCall httpCall, BidRequ } private static List extractBids(BidResponse bidResponse, BidRequest bidRequest) { - return bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid()) ? Collections - .emptyList() : bidsFromResponse(bidResponse, bidRequest.getImp()); + return bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid()) + ? Collections.emptyList() + : bidsFromResponse(bidResponse, bidRequest.getImp()); } private static List bidsFromResponse(BidResponse bidResponse, List imps) { diff --git a/src/main/java/org/prebid/server/bidder/triplelift/TripleliftBidder.java b/src/main/java/org/prebid/server/bidder/triplelift/TripleliftBidder.java index 213133fa17c..e57108b2934 100644 --- a/src/main/java/org/prebid/server/bidder/triplelift/TripleliftBidder.java +++ b/src/main/java/org/prebid/server/bidder/triplelift/TripleliftBidder.java @@ -80,7 +80,7 @@ private Imp modifyImp(Imp imp) throws PreBidException { final ExtImpTriplelift impExt = parseImpExt(imp); return imp.toBuilder() .tagid(impExt.getInventoryCode()) - .bidfloor(ObjectUtils.defaultIfNull(impExt.getFloor(), imp.getBidfloor())) + .bidfloor(ObjectUtils.getIfNull(impExt.getFloor(), imp.getBidfloor())) .build(); } diff --git a/src/main/java/org/prebid/server/bidder/unicorn/UnicornBidder.java b/src/main/java/org/prebid/server/bidder/unicorn/UnicornBidder.java index 9648ff08a40..db15d3e61e2 100644 --- a/src/main/java/org/prebid/server/bidder/unicorn/UnicornBidder.java +++ b/src/main/java/org/prebid/server/bidder/unicorn/UnicornBidder.java @@ -111,7 +111,7 @@ private Imp modifyImp(Imp imp) { .secure(1) .tagid(resolvedPlacementId != null ? resolvedPlacementId : placementId) .ext(mapper.mapper().convertValue( - ObjectUtils.defaultIfNull(resolvedUnicornImpExt, unicornImpExt), + ObjectUtils.getIfNull(resolvedUnicornImpExt, unicornImpExt), ObjectNode.class)) .build(); } diff --git a/src/main/java/org/prebid/server/bidder/vidoomy/VidoomyBidder.java b/src/main/java/org/prebid/server/bidder/vidoomy/VidoomyBidder.java index 68cb8709694..54dc9239b5b 100644 --- a/src/main/java/org/prebid/server/bidder/vidoomy/VidoomyBidder.java +++ b/src/main/java/org/prebid/server/bidder/vidoomy/VidoomyBidder.java @@ -93,7 +93,7 @@ private static void validateBannerSizes(Integer width, Integer height, List
measureExtractor) { - return ObjectUtils.defaultIfNull(ObjectUtil.getIfNotNull(format, measureExtractor), 0); + return ObjectUtils.getIfNull(ObjectUtil.getIfNotNull(format, measureExtractor), 0); } private HttpRequest createRequest(BidRequest bidRequest, Imp imp) { diff --git a/src/main/java/org/prebid/server/bidder/visiblemeasures/VisibleMeasuresBidder.java b/src/main/java/org/prebid/server/bidder/visiblemeasures/VisibleMeasuresBidder.java index 88a4fb92413..ca6bc173e31 100644 --- a/src/main/java/org/prebid/server/bidder/visiblemeasures/VisibleMeasuresBidder.java +++ b/src/main/java/org/prebid/server/bidder/visiblemeasures/VisibleMeasuresBidder.java @@ -84,7 +84,7 @@ private ObjectNode resolveImpExt(ExtImpVisibleMeasures extImpVisibleMeasures) { final String placementId = extImpVisibleMeasures.getPlacementId(); final String endpointId = extImpVisibleMeasures.getEndpointId(); - final VisibleMeasuresType type = ObjectUtils.defaultIfNull( + final VisibleMeasuresType type = ObjectUtils.getIfNull( StringUtils.isNotEmpty(placementId) ? VisibleMeasuresType.PUBLISHER : null, StringUtils.isNotEmpty(endpointId) ? VisibleMeasuresType.NETWORK : null); diff --git a/src/main/java/org/prebid/server/bidder/vungle/VungleBidder.java b/src/main/java/org/prebid/server/bidder/vungle/VungleBidder.java index aa16a4367f1..f10a2dcc453 100644 --- a/src/main/java/org/prebid/server/bidder/vungle/VungleBidder.java +++ b/src/main/java/org/prebid/server/bidder/vungle/VungleBidder.java @@ -11,6 +11,7 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -81,7 +82,7 @@ public Result>> makeHttpRequests(BidRequest bidRequ private Price resolveBidFloor(Imp imp, BidRequest bidRequest) { BigDecimal bigDecimal = null; if (BidderUtil.isValidPrice(imp.getBidfloor()) - && !StringUtils.equalsIgnoreCase(imp.getBidfloorcur(), BIDDER_CURRENCY) + && !Strings.CI.equals(imp.getBidfloorcur(), BIDDER_CURRENCY) && StringUtils.isNotBlank(imp.getBidfloorcur())) { bigDecimal = currencyConversionService.convertCurrency( imp.getBidfloor(), bidRequest, imp.getBidfloorcur(), BIDDER_CURRENCY); diff --git a/src/main/java/org/prebid/server/bidder/yahooads/YahooAdsBidder.java b/src/main/java/org/prebid/server/bidder/yahooads/YahooAdsBidder.java index 3e15eb554a3..800f21f2c9c 100644 --- a/src/main/java/org/prebid/server/bidder/yahooads/YahooAdsBidder.java +++ b/src/main/java/org/prebid/server/bidder/yahooads/YahooAdsBidder.java @@ -1,10 +1,8 @@ package org.prebid.server.bidder.yahooads; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.IntNode; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.node.TextNode; import com.iab.openrtb.request.App; import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; @@ -20,8 +18,6 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.prebid.server.auction.versionconverter.BidRequestOrtbVersionConversionManager; -import org.prebid.server.auction.versionconverter.OrtbVersion; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -32,9 +28,7 @@ import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; -import org.prebid.server.proto.openrtb.ext.FlexibleExtension; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; -import org.prebid.server.proto.openrtb.ext.request.ExtRegsDsa; import org.prebid.server.proto.openrtb.ext.request.yahooads.ExtImpYahooAds; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; @@ -44,7 +38,6 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Optional; public class YahooAdsBidder implements Bidder { @@ -52,16 +45,17 @@ public class YahooAdsBidder implements Bidder { new TypeReference<>() { }; + private static final String OPENRTB_VERSION = "2.6"; + private static final String GPP_PROPERTY = "gpp"; + private static final String GPP_SID_PROPERTY = "gpp_sid"; + private final String endpointUrl; - private final BidRequestOrtbVersionConversionManager conversionManager; private final JacksonMapper mapper; public YahooAdsBidder(String endpointUrl, - BidRequestOrtbVersionConversionManager conversionManager, JacksonMapper mapper) { this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); this.mapper = Objects.requireNonNull(mapper); - this.conversionManager = Objects.requireNonNull(conversionManager); } @Override @@ -70,16 +64,14 @@ public Result>> makeHttpRequests(BidRequest bidRequ final List errors = new ArrayList<>(); final Regs regs = bidRequest.getRegs(); - final BidRequest bidRequestOpenRtb25 = this.conversionManager.convertFromAuctionSupportedVersion(bidRequest, - OrtbVersion.ORTB_2_5); + final Regs modifiedRegs = regs != null ? modifyRegs(regs) : null; - final List impList = bidRequestOpenRtb25.getImp(); + final List impList = bidRequest.getImp(); for (int i = 0; i < impList.size(); i++) { try { final Imp imp = impList.get(i); final ExtImpYahooAds extImpYahooAds = parseAndValidateImpExt(imp.getExt(), i); - final BidRequest modifiedRequest = modifyRequest(bidRequestOpenRtb25, imp, extImpYahooAds, - regs); + final BidRequest modifiedRequest = modifyRequest(bidRequest, imp, extImpYahooAds, modifiedRegs); bidRequests.add(makeHttpRequest(modifiedRequest)); } catch (PreBidException e) { errors.add(BidderError.badInput(e.getMessage())); @@ -111,8 +103,7 @@ private ExtImpYahooAds parseAndValidateImpExt(ObjectNode impExtNode, int index) return extImpYahooAds; } - private BidRequest modifyRequest(BidRequest request, Imp imp, ExtImpYahooAds extImpYahooAds, - Regs regs) { + private BidRequest modifyRequest(BidRequest request, Imp imp, ExtImpYahooAds extImpYahooAds, Regs regs) { final BidRequest.BidRequestBuilder requestBuilder = request.toBuilder(); final Site site = request.getSite(); @@ -125,7 +116,7 @@ private BidRequest modifyRequest(BidRequest request, Imp imp, ExtImpYahooAds ext } if (regs != null) { - requestBuilder.regs(modifyRegs(regs)); + requestBuilder.regs(regs); } return requestBuilder @@ -171,49 +162,66 @@ private static Banner modifyBanner(Banner banner) { } private Regs modifyRegs(Regs regs) { - final ExtRegs extRegs = resolveExtRegs(regs); - - return Regs.builder().ext(extRegs).build(); - } + final ExtRegs ext = regs.getExt(); + if (ext == null || !(ext.containsProperty(GPP_PROPERTY) || ext.containsProperty(GPP_SID_PROPERTY))) { + return regs; + } - private ExtRegs resolveExtRegs(Regs regs) { - final Integer gdpr = resolveGdpr(regs); - final String usPrivacy = resolveUsPrivacy(regs); final String gpp = regs.getGpp(); + final String resolvedGpp = gpp == null ? gppToPromote(ext) : gpp; + final List gppSid = regs.getGppSid(); + final List resolvedGppSid = CollectionUtils.isEmpty(gppSid) ? gppSidToPromote(ext) : gppSid; - final String gpc = Optional.ofNullable(regs.getExt()) - .map(ExtRegs::getGpc) - .orElse(null); - final ExtRegsDsa dsa = Optional.ofNullable(regs.getExt()) - .map(ExtRegs::getDsa) - .orElse(null); - final ExtRegs extRegs = ExtRegs.of(gdpr, usPrivacy, gpc, dsa); - extRegs.addProperty("gpp", TextNode.valueOf(gpp)); - if (!CollectionUtils.isEmpty(gppSid)) { - final ArrayNode gppArrayNode = mapper.mapper().createArrayNode(); - gppSid.forEach(gppArrayNode::add); - extRegs.addProperty("gpp_sid", gppArrayNode); + final ExtRegs modifiedExt = copy(ext); + if (resolvedGpp != null) { + modifiedExt.removeProperty(GPP_PROPERTY); } - if (regs.getCoppa() != null) { - extRegs.addProperty("coppa", IntNode.valueOf(regs.getCoppa())); + if (CollectionUtils.isNotEmpty(resolvedGppSid)) { + modifiedExt.removeProperty(GPP_SID_PROPERTY); } - Optional.ofNullable(regs.getExt()) - .map(FlexibleExtension::getProperties) - .ifPresent(extRegs::addProperties); + return regs.toBuilder() + .gpp(resolvedGpp) + .gppSid(resolvedGppSid) + .ext(isExtEmpty(modifiedExt) ? null : modifiedExt) + .build(); + } + + private static String gppToPromote(ExtRegs ext) { + final JsonNode node = ext.getProperty(GPP_PROPERTY); + return node != null && node.isTextual() ? node.asText() : null; + } + + private static List gppSidToPromote(ExtRegs ext) { + final JsonNode node = ext.getProperty(GPP_SID_PROPERTY); + if (node == null || !node.isArray() || node.isEmpty()) { + return null; + } + + final List sids = new ArrayList<>(node.size()); + for (final JsonNode elem : node) { + if (!elem.isIntegralNumber() || !elem.canConvertToInt()) { + return null; + } + sids.add(elem.intValue()); + } - return extRegs; + return sids; } - private static Integer resolveGdpr(Regs regs) { - return regs.getGdpr() != null ? regs.getGdpr() - : (regs.getExt() != null ? regs.getExt().getGdpr() : null); + private ExtRegs copy(ExtRegs ext) { + final ExtRegs result = ExtRegs.of(ext.getGdpr(), ext.getUsPrivacy(), ext.getGpc(), ext.getDsa()); + mapper.fillExtension(result, ext.getProperties()); + return result; } - private static String resolveUsPrivacy(Regs regs) { - return regs.getUsPrivacy() != null ? regs.getUsPrivacy() - : (regs.getExt() != null ? regs.getExt().getUsPrivacy() : null); + private static boolean isExtEmpty(ExtRegs ext) { + return ext.getGdpr() == null + && ext.getUsPrivacy() == null + && ext.getGpc() == null + && ext.getDsa() == null + && ext.getProperties().isEmpty(); } private HttpRequest makeHttpRequest(BidRequest outgoingRequest) { @@ -228,7 +236,7 @@ private HttpRequest makeHttpRequest(BidRequest outgoingRequest) { private static MultiMap makeHeaders(Device device) { final MultiMap headers = HttpUtil.headers() - .add(HttpUtil.X_OPENRTB_VERSION_HEADER, "2.5"); + .add(HttpUtil.X_OPENRTB_VERSION_HEADER, OPENRTB_VERSION); final String deviceUa = device != null ? device.getUa() : null; HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.USER_AGENT_HEADER, deviceUa); diff --git a/src/main/java/org/prebid/server/bidder/yeahmobi/YeahmobiBidder.java b/src/main/java/org/prebid/server/bidder/yeahmobi/YeahmobiBidder.java index 2f40e569566..23c811f5f07 100644 --- a/src/main/java/org/prebid/server/bidder/yeahmobi/YeahmobiBidder.java +++ b/src/main/java/org/prebid/server/bidder/yeahmobi/YeahmobiBidder.java @@ -92,8 +92,8 @@ private Imp modifyImp(Imp imp) { return resolvedNativeRequest != null ? imp.toBuilder() - .xNative(impNative.toBuilder().request(resolvedNativeRequest).build()) - .build() + .xNative(impNative.toBuilder().request(resolvedNativeRequest).build()) + .build() : imp; } diff --git a/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java b/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java index 2af1f1b968f..f481599b2f6 100644 --- a/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java +++ b/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java @@ -265,7 +265,7 @@ private String resolveSupplyChain(SupplyChain schain) { schainBuilder.append(schain.getVer()); schainBuilder.append(","); - schainBuilder.append(ObjectUtils.defaultIfNull(schain.getComplete(), 0)); + schainBuilder.append(ObjectUtils.getIfNull(schain.getComplete(), 0)); for (SupplyChainNode node : schain.getNodes()) { schainBuilder.append("!"); schainBuilder.append(encodeValue(node.getAsi())); @@ -354,7 +354,7 @@ private static String encodeTransparency(DsaTransparency transparency) { private static String encodeTransparencyParams(List dsaParams) { return dsaParams.stream() - .map(param -> ObjectUtils.defaultIfNull(param, 0)) + .map(param -> ObjectUtils.getIfNull(param, 0)) .map(Object::toString) .collect(Collectors.joining(TRANSPARENCY_TEMPLATE_PARAMS_DELIMITER)); } diff --git a/src/main/java/org/prebid/server/bidder/zmaticoo/ZMaticooBidder.java b/src/main/java/org/prebid/server/bidder/zmaticoo/ZMaticooBidder.java index d2a8c6de6a9..07cc81b05c7 100644 --- a/src/main/java/org/prebid/server/bidder/zmaticoo/ZMaticooBidder.java +++ b/src/main/java/org/prebid/server/bidder/zmaticoo/ZMaticooBidder.java @@ -92,10 +92,10 @@ private Imp modifyImp(Imp imp) { final UpdateResult nativeRequest = resolveNativeRequest(xNative.getRequest()); return nativeRequest.isUpdated() ? imp.toBuilder() - .xNative(xNative.toBuilder() - .request(nativeRequest.getValue()) - .build()) - .build() + .xNative(xNative.toBuilder() + .request(nativeRequest.getValue()) + .build()) + .build() : imp; } @@ -169,7 +169,7 @@ private static BidderBid makeBidderBid(Bid bid, String currency, List BidType.banner; case 2 -> BidType.video; diff --git a/src/main/java/org/prebid/server/cache/CoreCacheService.java b/src/main/java/org/prebid/server/cache/CoreCacheService.java index c591e6090e7..c89507bc113 100644 --- a/src/main/java/org/prebid/server/cache/CoreCacheService.java +++ b/src/main/java/org/prebid/server/cache/CoreCacheService.java @@ -567,7 +567,7 @@ private void updateCreativeMetrics(List cachedCreatives, for (CachedCreative cachedCreative : cachedCreatives) { final BidPutObject payload = cachedCreative.getPayload(); final MetricName creativeType = resolveCreativeTypeName(payload); - final Integer creativeTtl = ObjectUtils.defaultIfNull(payload.getTtlseconds(), payload.getExpiry()); + final Integer creativeTtl = ObjectUtils.getIfNull(payload.getTtlseconds(), payload.getExpiry()); if (creativeTtl != null) { updateCreativeTtlMetric.accept(creativeTtl, creativeType); diff --git a/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java b/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java index d4e84bca9c3..cba3f4fd452 100644 --- a/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java +++ b/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java @@ -1,7 +1,7 @@ package org.prebid.server.cache.utils; import io.vertx.core.MultiMap; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.util.HttpUtil; import java.net.MalformedURLException; @@ -53,6 +53,6 @@ private static URL toUrl(String cacheSchema, } private static boolean startsWithSlashOrNull(String path) { - return path == null || StringUtils.startsWith(path, "/"); + return path == null || Strings.CS.startsWith(path, "/"); } } diff --git a/src/main/java/org/prebid/server/cookie/UidsCookieService.java b/src/main/java/org/prebid/server/cookie/UidsCookieService.java index 8bfe414884c..83755231ccb 100644 --- a/src/main/java/org/prebid/server/cookie/UidsCookieService.java +++ b/src/main/java/org/prebid/server/cookie/UidsCookieService.java @@ -5,6 +5,7 @@ import io.vertx.core.http.CookieSameSite; import io.vertx.ext.web.RoutingContext; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.cookie.model.UidWithExpiry; import org.prebid.server.cookie.proto.Uids; import org.prebid.server.json.DecodeException; @@ -352,7 +353,7 @@ private void updateSyncSizeMetrics(String nextCookieFamily) { } public String hostCookieUidToSync(RoutingContext routingContext, String cookieFamilyName) { - if (!StringUtils.equals(cookieFamilyName, hostCookieFamily)) { + if (!Strings.CS.equals(cookieFamilyName, hostCookieFamily)) { return null; } @@ -366,7 +367,7 @@ public String hostCookieUidToSync(RoutingContext routingContext, String cookieFa .map(Uids::getUids) .map(uids -> uids.get(cookieFamilyName)) .map(UidWithExpiry::getUid) - .filter(uid -> StringUtils.equals(hostCookieUid, uid)) + .filter(uid -> Strings.CS.equals(hostCookieUid, uid)) .isPresent(); return inSync ? null : hostCookieUid; diff --git a/src/main/java/org/prebid/server/cookie/exception/CookieSyncException.java b/src/main/java/org/prebid/server/cookie/exception/CookieSyncException.java index 4f8921303ac..d57560d19f0 100644 --- a/src/main/java/org/prebid/server/cookie/exception/CookieSyncException.java +++ b/src/main/java/org/prebid/server/cookie/exception/CookieSyncException.java @@ -6,11 +6,6 @@ public class CookieSyncException extends RuntimeException { public final TcfContext tcfContext; - public CookieSyncException(String error, Throwable cause, TcfContext tcfContext) { - super(error, cause); - this.tcfContext = tcfContext; - } - public CookieSyncException(Throwable error, TcfContext tcfContext) { super(error); this.tcfContext = tcfContext; diff --git a/src/main/java/org/prebid/server/currency/CurrencyConversionService.java b/src/main/java/org/prebid/server/currency/CurrencyConversionService.java index ab398f877cd..ed9794b0138 100644 --- a/src/main/java/org/prebid/server/currency/CurrencyConversionService.java +++ b/src/main/java/org/prebid/server/currency/CurrencyConversionService.java @@ -247,7 +247,7 @@ private static BigDecimal getConversionRateByPriority(Map messages) { super(String.join("\n", messages)); this.messages = messages; diff --git a/src/main/java/org/prebid/server/execution/file/supplier/RemoteFileSupplier.java b/src/main/java/org/prebid/server/execution/file/supplier/RemoteFileSupplier.java index 855ee4e8f9d..fc3cffc5248 100644 --- a/src/main/java/org/prebid/server/execution/file/supplier/RemoteFileSupplier.java +++ b/src/main/java/org/prebid/server/execution/file/supplier/RemoteFileSupplier.java @@ -60,10 +60,10 @@ public RemoteFileSupplier(String downloadUrl, .setFollowRedirects(true); headRequestOptions = checkRemoteFileSize ? new RequestOptions() - .setMethod(HttpMethod.HEAD) - .setTimeout(timeout) - .setAbsoluteURI(downloadUrl) - .setFollowRedirects(true) + .setMethod(HttpMethod.HEAD) + .setTimeout(timeout) + .setAbsoluteURI(downloadUrl) + .setFollowRedirects(true) : null; } @@ -71,15 +71,15 @@ public RemoteFileSupplier(String downloadUrl, public Future get() { return isDownloadRequired().compose(isDownloadRequired -> isDownloadRequired ? Future.all(downloadFile(), createBackup()) - .compose(ignored -> tmpToSave()) - .map(savePath) + .compose(ignored -> tmpToSave()) + .map(savePath) : Future.succeededFuture()); } private Future isDownloadRequired() { return headRequestOptions != null ? fileSystem.exists(savePath) - .compose(exists -> exists ? isSizeChanged() : Future.succeededFuture(true)) + .compose(exists -> exists ? isSizeChanged() : Future.succeededFuture(true)) : Future.succeededFuture(true); } @@ -145,7 +145,7 @@ public Future restoreFromBackup() { return fileSystem.exists(backupPath) .compose(exists -> exists ? copyFile(backupPath, savePath) - .onSuccess(ignored -> deleteFile(backupPath)) + .onSuccess(ignored -> deleteFile(backupPath)) : Future.succeededFuture()); } diff --git a/src/main/java/org/prebid/server/execution/file/syncer/FileSyncer.java b/src/main/java/org/prebid/server/execution/file/syncer/FileSyncer.java index fd850e126c4..c1ac867b5a5 100644 --- a/src/main/java/org/prebid/server/execution/file/syncer/FileSyncer.java +++ b/src/main/java/org/prebid/server/execution/file/syncer/FileSyncer.java @@ -47,8 +47,8 @@ private void sync(RetryPolicy currentRetryPolicy) { private Future processFile(String filePath) { return filePath != null ? vertx.executeBlocking(() -> fileProcessor.setDataPath(filePath)) - .compose(Function.identity()) - .onFailure(error -> logger.error("Can't process saved file: " + filePath)) + .compose(Function.identity()) + .onFailure(error -> logger.error("Can't process saved file: " + filePath)) : Future.succeededFuture(); } diff --git a/src/main/java/org/prebid/server/floors/BasicPriceFloorAdjuster.java b/src/main/java/org/prebid/server/floors/BasicPriceFloorAdjuster.java index d943c6b92e9..42fa6c2c5ce 100644 --- a/src/main/java/org/prebid/server/floors/BasicPriceFloorAdjuster.java +++ b/src/main/java/org/prebid/server/floors/BasicPriceFloorAdjuster.java @@ -95,11 +95,11 @@ private static ExtRequestBidAdjustmentFactors extractBidAdjustmentFactors(BidReq private static boolean shouldAdjustBidFloor(BidRequest bidRequest, Account account) { final Boolean shouldAdjustBidFloor = - ObjectUtils.defaultIfNull( + ObjectUtils.getIfNull( shouldAdjustBidFloorByRequest(bidRequest), shouldAdjustBidFloorByAccount(account)); - return ObjectUtils.defaultIfNull(shouldAdjustBidFloor, true); + return ObjectUtils.getIfNull(shouldAdjustBidFloor, true); } private static Set retrieveImpMediaTypes(Imp imp) { diff --git a/src/main/java/org/prebid/server/floors/BasicPriceFloorEnforcer.java b/src/main/java/org/prebid/server/floors/BasicPriceFloorEnforcer.java index 2252a8fad54..2e5d07e7bbf 100644 --- a/src/main/java/org/prebid/server/floors/BasicPriceFloorEnforcer.java +++ b/src/main/java/org/prebid/server/floors/BasicPriceFloorEnforcer.java @@ -7,11 +7,11 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.auction.model.AuctionParticipation; +import org.prebid.server.auction.model.BidRejection; import org.prebid.server.auction.model.BidRejectionReason; import org.prebid.server.auction.model.BidRejectionTracker; import org.prebid.server.auction.model.BidderRequest; import org.prebid.server.auction.model.BidderResponse; -import org.prebid.server.auction.model.BidRejection; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderError; import org.prebid.server.bidder.model.BidderSeatBid; @@ -163,7 +163,7 @@ private AuctionParticipation applyEnforcement(BidRequest bidRequest, } final BigDecimal price = bid.getPrice(); - final Map originalPriceFloors = Optional.ofNullable(auctionParticipation.getBidderRequest()) + final Map originalPriceFloors = Optional.of(auctionParticipation.getBidderRequest()) .map(BidderRequest::getOriginalPriceFloors) .orElse(Collections.emptyMap()); @@ -258,7 +258,7 @@ private BigDecimal convertIfRequired(BigDecimal floor, BidRequest bidderBidRequest, BidRequest bidRequest) { - final String resolvedFloorCurrency = ObjectUtils.defaultIfNull(floorCurrency, + final String resolvedFloorCurrency = ObjectUtils.getIfNull(floorCurrency, resolveBidRequestCurrency(bidderBidRequest)); final String bidRequestCurrency = resolveBidRequestCurrency(bidRequest); diff --git a/src/main/java/org/prebid/server/floors/BasicPriceFloorProcessor.java b/src/main/java/org/prebid/server/floors/BasicPriceFloorProcessor.java index 6389139a5ac..d0f72726859 100644 --- a/src/main/java/org/prebid/server/floors/BasicPriceFloorProcessor.java +++ b/src/main/java/org/prebid/server/floors/BasicPriceFloorProcessor.java @@ -86,7 +86,7 @@ public BasicPriceFloorProcessor(PriceFloorFetcher floorFetcher, } private static int resolveModelGroupWeight(PriceFloorModelGroup modelGroup) { - return ObjectUtils.defaultIfNull(modelGroup.getModelWeight(), 1); + return ObjectUtils.getIfNull(modelGroup.getModelWeight(), 1); } @Override @@ -356,7 +356,7 @@ private List updateImpsWithFloors(PriceFloorRules effectiveFloors, final List imps = bidRequest.getImp(); final ExtRequestPrebid prebid = ObjectUtil.getIfNotNull(bidRequest.getExt(), ExtRequest::getPrebid); - final PriceFloorRules floors = ObjectUtils.defaultIfNull( + final PriceFloorRules floors = ObjectUtils.getIfNull( effectiveFloors, ObjectUtil.getIfNotNull(prebid, ExtRequestPrebid::getFloors)); diff --git a/src/main/java/org/prebid/server/floors/BasicPriceFloorResolver.java b/src/main/java/org/prebid/server/floors/BasicPriceFloorResolver.java index f726755e9f8..72955f133ec 100644 --- a/src/main/java/org/prebid/server/floors/BasicPriceFloorResolver.java +++ b/src/main/java/org/prebid/server/floors/BasicPriceFloorResolver.java @@ -20,6 +20,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.model.Price; import org.prebid.server.currency.CurrencyConversionService; import org.prebid.server.exception.PreBidException; @@ -140,7 +141,7 @@ public PriceFloorResult resolve(BidRequest bidRequest, final Map values = keysToLowerCase(modelGroup.getValues()); final PrebidConfigSource source = SimpleSource.of( WILDCARD_CATCH_ALL, - ObjectUtils.defaultIfNull(schema.getDelimiter(), SCHEMA_DEFAULT_DELIMITER), + ObjectUtils.getIfNull(schema.getDelimiter(), SCHEMA_DEFAULT_DELIMITER), values.keySet()); final PrebidConfigParameters parameters = createParameters(schema, bidRequest, imp, mediaType, format, bidder); @@ -477,11 +478,11 @@ private PriceFloorResult resolveResult(BigDecimal floor, final BigDecimal floorMin = floorMinValues.getValue(); final String floorMinCur = floorMinValues.getCurrency(); - final String effectiveRulesCurrency = ObjectUtils.defaultIfNull(rulesCurrency, DEFAULT_RULES_CURRENCY); + final String effectiveRulesCurrency = ObjectUtils.getIfNull(rulesCurrency, DEFAULT_RULES_CURRENCY); final String effectiveFloorMinCurrency = ObjectUtils.firstNonNull(floorMinCur, rulesCurrency, DEFAULT_RULES_CURRENCY); - final BigDecimal convertedFloorMinValue = !StringUtils.equals(effectiveRulesCurrency, effectiveFloorMinCurrency) + final BigDecimal convertedFloorMinValue = !Strings.CS.equals(effectiveRulesCurrency, effectiveFloorMinCurrency) ? currencyConversionService.convertCurrency( floorMin, bidRequest, @@ -525,8 +526,8 @@ private Price resolveFloorMin(BidRequest bidRequest, Imp imp, List warni } return Price.of( - ObjectUtils.defaultIfNull(impFloorMinCur, requestFloorMinCur), - ObjectUtils.defaultIfNull(impFloorMin, requestFloorMin)); + ObjectUtils.getIfNull(impFloorMinCur, requestFloorMinCur), + ObjectUtils.getIfNull(impFloorMin, requestFloorMin)); } private ExtImpPrebid extImpPrebid(JsonNode extImpPrebid) { @@ -551,14 +552,14 @@ private static Price resolvePrice(Price floor, Price convertedFloorMin, Price fl final BigDecimal floorMinValue = ObjectUtil.getIfNotNull(convertedFloorMin, Price::getValue); final String floorMinCurrency = ObjectUtil.getIfNotNull(floor, Price::getCurrency); - if (StringUtils.equals(floorCurrency, floorMinCurrency) && floorValue != null && floorMinValue != null) { + if (Strings.CS.equals(floorCurrency, floorMinCurrency) && floorValue != null && floorMinValue != null) { return floorValue.compareTo(floorMinValue) > 0 ? roundPrice(floor) : roundPrice(convertedFloorMin); } - return roundPrice(ObjectUtils.defaultIfNull(floor, floorMin)); + return roundPrice(ObjectUtils.getIfNull(floor, floorMin)); } private static Price roundPrice(Price price) { diff --git a/src/main/java/org/prebid/server/floors/NoSignalBidderPriceFloorAdjuster.java b/src/main/java/org/prebid/server/floors/NoSignalBidderPriceFloorAdjuster.java index b1273311049..8665b10caed 100644 --- a/src/main/java/org/prebid/server/floors/NoSignalBidderPriceFloorAdjuster.java +++ b/src/main/java/org/prebid/server/floors/NoSignalBidderPriceFloorAdjuster.java @@ -4,7 +4,7 @@ import com.iab.openrtb.request.Imp; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.model.Price; import org.prebid.server.floors.model.PriceFloorData; import org.prebid.server.floors.model.PriceFloorEnforcement; @@ -68,7 +68,7 @@ public Price adjustForImp(Imp imp, } private static boolean isNoSignalBidder(String bidder, List noSignalBidders) { - return noSignalBidders.stream().anyMatch(noSignalBidder -> StringUtils.equalsIgnoreCase(noSignalBidder, bidder)) + return noSignalBidders.stream().anyMatch(noSignalBidder -> Strings.CI.equals(noSignalBidder, bidder)) || noSignalBidders.contains(ALL_BIDDERS); } } diff --git a/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java b/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java index 960ffc5f46c..ecfa59578e4 100644 --- a/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java +++ b/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java @@ -264,7 +264,7 @@ private Long createMaxAgeTimer(String accountId, long cacheTtl) { } final Long effectiveCacheTtl = - ObjectUtils.defaultIfNull( + ObjectUtils.getIfNull( ObjectUtil.getIfNotNull(debugProperties, PriceFloorDebugProperties::getMinMaxAgeSec), cacheTtl); @@ -299,7 +299,7 @@ private PriceFloorData createPeriodicTimerForRulesFetch(PriceFloorData priceFloo final long accountPeriodicTimeSec = ObjectUtil.getIfNotNull(fetchConfig, AccountPriceFloorsFetchConfig::getPeriodSec); final long periodicTimeSec = - ObjectUtils.defaultIfNull( + ObjectUtils.getIfNull( ObjectUtil.getIfNotNull(debugProperties, PriceFloorDebugProperties::getMinPeriodSec), accountPeriodicTimeSec); vertx.setTimer(TimeUnit.SECONDS.toMillis(periodicTimeSec), ignored -> periodicFetch(accountId)); diff --git a/src/main/java/org/prebid/server/floors/PriceFloorsConfigResolver.java b/src/main/java/org/prebid/server/floors/PriceFloorsConfigResolver.java index 14834e24b7c..801f1a522e0 100644 --- a/src/main/java/org/prebid/server/floors/PriceFloorsConfigResolver.java +++ b/src/main/java/org/prebid/server/floors/PriceFloorsConfigResolver.java @@ -100,7 +100,7 @@ private static void validatePriceFloorsFetchConfig(AccountPriceFloorsFetchConfig return; } - final long maxAgeSec = ObjectUtils.defaultIfNull(fetchConfig.getMaxAgeSec(), DEFAULT_MAX_AGE_SEC_VALUE); + final long maxAgeSec = ObjectUtils.getIfNull(fetchConfig.getMaxAgeSec(), DEFAULT_MAX_AGE_SEC_VALUE); if (isNotInRange(maxAgeSec, MIN_MAX_AGE_SEC_VALUE, MAX_AGE_SEC_VALUE)) { throw new PreBidException(invalidPriceFloorsPropertyMessage("max-age-sec", maxAgeSec)); } diff --git a/src/main/java/org/prebid/server/handler/CookieSyncHandler.java b/src/main/java/org/prebid/server/handler/CookieSyncHandler.java index cf332416092..b3dce7e60a7 100644 --- a/src/main/java/org/prebid/server/handler/CookieSyncHandler.java +++ b/src/main/java/org/prebid/server/handler/CookieSyncHandler.java @@ -233,20 +233,20 @@ private void respondWithError(Throwable error, RoutingContext routingContext) { final String body; switch (error) { - case InvalidCookieSyncRequestException invalidCookieSyncRequestException -> { + case InvalidCookieSyncRequestException _ -> { status = HttpResponseStatus.BAD_REQUEST; body = "Invalid request format: " + message; metrics.updateUserSyncBadRequestMetric(); badRequestLogger.info(message, logSamplingRate); } - case UnauthorizedUidsException unauthorizedUidsException -> { + case UnauthorizedUidsException _ -> { status = HttpResponseStatus.UNAUTHORIZED; body = "Unauthorized: " + message; metrics.updateUserSyncOptoutMetric(); } - case InvalidAccountConfigException invalidAccountConfigException -> { + case InvalidAccountConfigException _ -> { status = HttpResponseStatus.BAD_REQUEST; body = "Invalid account configuration: " + message; diff --git a/src/main/java/org/prebid/server/handler/ExceptionHandler.java b/src/main/java/org/prebid/server/handler/ExceptionHandler.java index 1bff922f5c3..19d65f2287c 100644 --- a/src/main/java/org/prebid/server/handler/ExceptionHandler.java +++ b/src/main/java/org/prebid/server/handler/ExceptionHandler.java @@ -2,6 +2,7 @@ import io.vertx.core.Handler; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; import org.prebid.server.metric.Metrics; @@ -38,7 +39,7 @@ private static boolean shouldLogException(Throwable exception) { private static boolean isConnectionResetException(Throwable exception) { return exception instanceof IOException - && StringUtils.equals("recvAddress(..) failed: Connection reset by peer", exception.getMessage()); + && Strings.CS.equals("recvAddress(..) failed: Connection reset by peer", exception.getMessage()); } private static String errorMessageFrom(Throwable exception) { diff --git a/src/main/java/org/prebid/server/handler/GetVtrackHandler.java b/src/main/java/org/prebid/server/handler/GetVtrackHandler.java index e70e26627fc..aff360bb5f7 100644 --- a/src/main/java/org/prebid/server/handler/GetVtrackHandler.java +++ b/src/main/java/org/prebid/server/handler/GetVtrackHandler.java @@ -78,7 +78,7 @@ private static void respondWith(RoutingContext routingContext, Endpoint.vtrack, response -> { headers.forEach(response::putHeader); - response.setStatusCode(status.code()) .end(body); + response.setStatusCode(status.code()).end(body); }); } diff --git a/src/main/java/org/prebid/server/handler/PostVtrackHandler.java b/src/main/java/org/prebid/server/handler/PostVtrackHandler.java index c52068427ce..f62782f51a0 100644 --- a/src/main/java/org/prebid/server/handler/PostVtrackHandler.java +++ b/src/main/java/org/prebid/server/handler/PostVtrackHandler.java @@ -10,6 +10,7 @@ import io.vertx.ext.web.RoutingContext; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.BidderCatalog; import org.prebid.server.cache.CoreCacheService; import org.prebid.server.cache.proto.request.bid.BidCacheRequest; @@ -141,13 +142,13 @@ private static void validatePutObject(BidPutObject bidPutObject) { throw new IllegalArgumentException("'bidder' is required field and can't be empty"); } - if (!StringUtils.equals(bidPutObject.getType(), TYPE_XML)) { + if (!Strings.CS.equals(bidPutObject.getType(), TYPE_XML)) { throw new IllegalArgumentException("vtrack only accepts type xml"); } final JsonNode value = bidPutObject.getValue(); final String valueAsString = value != null ? value.asText() : null; - if (!StringUtils.containsIgnoreCase(valueAsString, " asyncAccount, final Integer accountTtl = accountVtrackTtl(account); final Set allowedBidders = biddersAllowingVastUpdate(vtrackPuts); coreCacheService.cachePutObjects( - vtrackPuts, isEventEnabled, allowedBidders, accountId, accountTtl, integration, timeout) + vtrackPuts, isEventEnabled, allowedBidders, accountId, accountTtl, integration, timeout) .onComplete(asyncCache -> handleCacheResult(asyncCache, routingContext)); } } diff --git a/src/main/java/org/prebid/server/handler/info/filters/BidderInfoFilterStrategy.java b/src/main/java/org/prebid/server/handler/info/filters/BidderInfoFilterStrategy.java index 2df354ff643..d3cd402bb51 100644 --- a/src/main/java/org/prebid/server/handler/info/filters/BidderInfoFilterStrategy.java +++ b/src/main/java/org/prebid/server/handler/info/filters/BidderInfoFilterStrategy.java @@ -1,7 +1,7 @@ package org.prebid.server.handler.info.filters; import io.vertx.ext.web.RoutingContext; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import java.util.function.Predicate; @@ -14,7 +14,7 @@ public interface BidderInfoFilterStrategy { static boolean lookUpQueryParamInContext(String queryParamName, RoutingContext routingContext) { final String queryParamValue = routingContext.queryParams().get(queryParamName); - if (queryParamValue != null && !StringUtils.equalsAnyIgnoreCase(queryParamValue, "true", "false")) { + if (queryParamValue != null && !Strings.CI.equalsAny(queryParamValue, "true", "false")) { throw new IllegalArgumentException( "Invalid value for '" + queryParamName + "' query param, must be of boolean type"); } diff --git a/src/main/java/org/prebid/server/handler/openrtb2/AmpHandler.java b/src/main/java/org/prebid/server/handler/openrtb2/AmpHandler.java index 1ee95db2813..e846652e3bb 100644 --- a/src/main/java/org/prebid/server/handler/openrtb2/AmpHandler.java +++ b/src/main/java/org/prebid/server/handler/openrtb2/AmpHandler.java @@ -284,13 +284,13 @@ private AmpResponse toAmpResponse(BidResponse bidResponse) { final Map targeting = new HashMap<>(seatBids == null ? Collections.emptyMap() : seatBids.stream() - .filter(Objects::nonNull) - .filter(seatBid -> seatBid.getBid() != null) - .flatMap(seatBid -> seatBid.getBid().stream() - .filter(Objects::nonNull) - .flatMap(bid -> targetingFrom(bid, seatBid.getSeat()).entrySet().stream())) - .map(entry -> Tuple2.of(entry.getKey(), TextNode.valueOf(entry.getValue()))) - .collect(Collectors.toMap(Tuple2::getLeft, Tuple2::getRight, (value1, value2) -> value2))); + .filter(Objects::nonNull) + .filter(seatBid -> seatBid.getBid() != null) + .flatMap(seatBid -> seatBid.getBid().stream() + .filter(Objects::nonNull) + .flatMap(bid -> targetingFrom(bid, seatBid.getSeat()).entrySet().stream())) + .map(entry -> Tuple2.of(entry.getKey(), TextNode.valueOf(entry.getValue()))) + .collect(Collectors.toMap(Tuple2::getLeft, Tuple2::getRight, (value1, value2) -> value2))); final Map additionalTargeting = extractAdditionalTargeting(bidResponse); targeting.putAll(additionalTargeting); @@ -433,7 +433,7 @@ private static String originFrom(RoutingContext routingContext) { } if (origin == null) { // Just to be safe - origin = ObjectUtils.defaultIfNull(routingContext.request().headers().get("Origin"), StringUtils.EMPTY); + origin = ObjectUtils.getIfNull(routingContext.request().headers().get("Origin"), StringUtils.EMPTY); } return origin; } diff --git a/src/main/java/org/prebid/server/handler/openrtb2/VideoHandler.java b/src/main/java/org/prebid/server/handler/openrtb2/VideoHandler.java index 0bb31bab72b..f21cf85d3d6 100644 --- a/src/main/java/org/prebid/server/handler/openrtb2/VideoHandler.java +++ b/src/main/java/org/prebid/server/handler/openrtb2/VideoHandler.java @@ -120,10 +120,9 @@ public void handle(RoutingContext routingContext) { .map(contextToErrors -> addToEvent(contextToErrors.getData(), videoEventBuilder::auctionContext, contextToErrors)) - .compose(contextToErrors -> - prepareSuccessfulResponse(contextToErrors, routingContext, videoEventBuilder) + .compose(podContext -> prepareSuccessfulResponse(podContext, routingContext, videoEventBuilder) .compose(this::invokeExitpointHooks) - .compose(context -> toVideoResponse(context.getAuctionContext(), contextToErrors.getPodErrors()) + .compose(context -> toVideoResponse(context.getAuctionContext(), podContext.getPodErrors()) .map(videoResponse -> addToEvent(videoResponse, videoEventBuilder::bidResponse, context))) .map(context -> diff --git a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java index 1761e402351..a5c1e3c7aaf 100644 --- a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java +++ b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java @@ -320,7 +320,7 @@ public Future> executeAuctionRe BidResponse bidResponse, AuctionContext auctionContext) { - final Account account = ObjectUtils.defaultIfNull(auctionContext.getAccount(), EMPTY_ACCOUNT); + final Account account = ObjectUtils.getIfNull(auctionContext.getAccount(), EMPTY_ACCOUNT); final HookExecutionContext context = auctionContext.getHookExecutionContext(); final HookHttpEndpoint endpoint = context.getEndpoint(); @@ -335,7 +335,7 @@ public Future> executeExitpointStage( String responseBody, AuctionContext auctionContext) { - final Account account = ObjectUtils.defaultIfNull(auctionContext.getAccount(), EMPTY_ACCOUNT); + final Account account = ObjectUtils.getIfNull(auctionContext.getAccount(), EMPTY_ACCOUNT); final HookExecutionContext context = auctionContext.getHookExecutionContext(); final HookHttpEndpoint endpoint = context.getEndpoint(); diff --git a/src/main/java/org/prebid/server/hooks/execution/provider/abtest/ABTestHookProvider.java b/src/main/java/org/prebid/server/hooks/execution/provider/abtest/ABTestHookProvider.java index 6a833ab2833..f3483aeb802 100644 --- a/src/main/java/org/prebid/server/hooks/execution/provider/abtest/ABTestHookProvider.java +++ b/src/main/java/org/prebid/server/hooks/execution/provider/abtest/ABTestHookProvider.java @@ -68,7 +68,7 @@ protected boolean shouldInvokeHook(String moduleCode, ABTest abTest) { return hookExecutionOutcome.getAction() != ExecutionAction.no_invocation; } - final int percent = ObjectUtils.defaultIfNull(abTest.getPercentActive(), 100); + final int percent = ObjectUtils.getIfNull(abTest.getPercentActive(), 100); return ThreadLocalRandom.current().nextInt(100) < percent; } diff --git a/src/main/java/org/prebid/server/json/JsonMerger.java b/src/main/java/org/prebid/server/json/JsonMerger.java index 999867b75b1..2fdfbce5684 100644 --- a/src/main/java/org/prebid/server/json/JsonMerger.java +++ b/src/main/java/org/prebid/server/json/JsonMerger.java @@ -47,7 +47,7 @@ public T merge(T originalObject, String storedData, String id, Class clas public T merge(T originalObject, T mergingObject, Class classToCast) { if (!ObjectUtils.allNotNull(originalObject, mergingObject)) { - return ObjectUtils.defaultIfNull(originalObject, mergingObject); + return ObjectUtils.getIfNull(originalObject, mergingObject); } final JsonNode originJsonNode = mapper.mapper().valueToTree(originalObject); diff --git a/src/main/java/org/prebid/server/json/deserializer/AccountActivityRulesConfigDeserializer.java b/src/main/java/org/prebid/server/json/deserializer/AccountActivityRulesConfigDeserializer.java index 2986e3a12a1..d29c4f5aef1 100644 --- a/src/main/java/org/prebid/server/json/deserializer/AccountActivityRulesConfigDeserializer.java +++ b/src/main/java/org/prebid/server/json/deserializer/AccountActivityRulesConfigDeserializer.java @@ -47,6 +47,6 @@ private static void reportWrongTokenException(JsonParser parser, Deserialization context.reportWrongTokenException( JsonToken.class, JsonToken.START_ARRAY, - "Failed to parse field %s to array with a reason: Expected array.".formatted(parser.getCurrentName())); + "Failed to parse field %s to array with a reason: Expected array.".formatted(parser.currentName())); } } diff --git a/src/main/java/org/prebid/server/json/deserializer/CommaSeparatedStringAsListOfIntegersDeserializer.java b/src/main/java/org/prebid/server/json/deserializer/CommaSeparatedStringAsListOfIntegersDeserializer.java index 0bd9db9f0e3..8b568447233 100644 --- a/src/main/java/org/prebid/server/json/deserializer/CommaSeparatedStringAsListOfIntegersDeserializer.java +++ b/src/main/java/org/prebid/server/json/deserializer/CommaSeparatedStringAsListOfIntegersDeserializer.java @@ -43,7 +43,7 @@ private static void reportWrongTokenException(JsonParser parser, Deserialization JsonToken.VALUE_STRING, """ Failed to parse field %s to List type with a reason: \ - Expected comma-separated string.""".formatted(parser.getCurrentName())); + Expected comma-separated string.""".formatted(parser.currentName())); } private static List parseList(String value) throws NumberFormatException { @@ -59,9 +59,9 @@ private static void reportPropertyInputMismatch(JsonParser parser, Deserializati context.reportPropertyInputMismatch( JsonToken.class, - parser.getCurrentName(), + parser.currentName(), """ Failed to parse field %s to List type with a reason: \ - NumberFormatException %s""".formatted(parser.getCurrentName(), cause)); + NumberFormatException %s""".formatted(parser.currentName(), cause)); } } diff --git a/src/main/java/org/prebid/server/json/deserializer/IntegerFlagDeserializer.java b/src/main/java/org/prebid/server/json/deserializer/IntegerFlagDeserializer.java index f92f49393f6..548403bee5c 100644 --- a/src/main/java/org/prebid/server/json/deserializer/IntegerFlagDeserializer.java +++ b/src/main/java/org/prebid/server/json/deserializer/IntegerFlagDeserializer.java @@ -28,7 +28,7 @@ public Integer deserialize(JsonParser parser, DeserializationContext ctxt) throw JsonToken.VALUE_NUMBER_INT, """ Failed to parse field %s to Integer type with a reason: \ - Expected type boolean or integer(`0` or `1`).""".formatted(parser.getCurrentName())); + Expected type boolean or integer(`0` or `1`).""".formatted(parser.currentName())); // the previous method should have thrown throw new AssertionError(); } diff --git a/src/main/java/org/prebid/server/log/ConditionalLogger.java b/src/main/java/org/prebid/server/log/ConditionalLogger.java index 90d642d57fa..c8d5621d00e 100644 --- a/src/main/java/org/prebid/server/log/ConditionalLogger.java +++ b/src/main/java/org/prebid/server/log/ConditionalLogger.java @@ -74,7 +74,7 @@ private static void log(String message, double samplingRate, Consumer lo } private void log(String message, long duration, TimeUnit unit, Consumer logger) { - final String key = ObjectUtils.defaultIfNull(this.key, message); + final String key = ObjectUtils.getIfNull(this.key, message); final Instant currentTime = Instant.now(); final Instant endTime = messageToWaitEndTime.get(key); diff --git a/src/main/java/org/prebid/server/metric/Metrics.java b/src/main/java/org/prebid/server/metric/Metrics.java index 06c31bb1895..693da456828 100644 --- a/src/main/java/org/prebid/server/metric/Metrics.java +++ b/src/main/java/org/prebid/server/metric/Metrics.java @@ -277,6 +277,10 @@ public void updateAccountRequestRejectedByFailedFetch(String accountId) { updateAccountRequestsMetrics(accountId, MetricName.rejected_by_account_fetch_failed); } + public void updateAccountRequestGotbidsMetric(String accountId) { + updateAccountRequestsMetrics(accountId, MetricName.gotbids); + } + private void updateAccountRequestsMetrics(String accountId, MetricName metricName) { forAccount(accountId).requests().incCounter(metricName); } diff --git a/src/main/java/org/prebid/server/privacy/HostVendorTcfDefinerService.java b/src/main/java/org/prebid/server/privacy/HostVendorTcfDefinerService.java index 1588f1827af..e72afb6f89b 100644 --- a/src/main/java/org/prebid/server/privacy/HostVendorTcfDefinerService.java +++ b/src/main/java/org/prebid/server/privacy/HostVendorTcfDefinerService.java @@ -44,7 +44,7 @@ public Future isAllowedForHostVendorId(TcfContext tcfCont return gdprHostVendorId == null ? Future.succeededFuture(HostVendorTcfResponse.allowedVendor()) : tcfDefinerService.resultForVendorIds(Collections.singleton(gdprHostVendorId), tcfContext) - .map(this::toHostVendorTcfResponse); + .map(this::toHostVendorTcfResponse); } private HostVendorTcfResponse toHostVendorTcfResponse(TcfResponse tcfResponse) { diff --git a/src/main/java/org/prebid/server/privacy/ccpa/Ccpa.java b/src/main/java/org/prebid/server/privacy/ccpa/Ccpa.java index 9bbb38699f8..6388249c4be 100644 --- a/src/main/java/org/prebid/server/privacy/ccpa/Ccpa.java +++ b/src/main/java/org/prebid/server/privacy/ccpa/Ccpa.java @@ -2,6 +2,7 @@ import lombok.Value; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.exception.PreBidException; @Value(staticConstructor = "of") @@ -36,7 +37,7 @@ public boolean isEnforced() { } final String optOutSale = Character.toString(usPrivacy.charAt(OPT_OUT_SALE_INDEX)); - return StringUtils.equalsIgnoreCase(optOutSale, ENFORCED_SIGNAL); + return Strings.CI.equals(optOutSale, ENFORCED_SIGNAL); } public static boolean isValid(String consent) { @@ -63,7 +64,7 @@ public static void validateUsPrivacy(String consent) { } private static void agreementSpecified(char agreement, String agreementType) { - final boolean isAppropriateValue = StringUtils.equalsAnyIgnoreCase(Character.toString(agreement), + final boolean isAppropriateValue = Strings.CI.equalsAny(Character.toString(agreement), NOT_ENFORCED_SIGNAL, ENFORCED_SIGNAL, NOT_DEFINED_SIGNAL); if (!isAppropriateValue) { diff --git a/src/main/java/org/prebid/server/privacy/gdpr/Tcf2Service.java b/src/main/java/org/prebid/server/privacy/gdpr/Tcf2Service.java index 6010ad950e2..9dde8f082b7 100644 --- a/src/main/java/org/prebid/server/privacy/gdpr/Tcf2Service.java +++ b/src/main/java/org/prebid/server/privacy/gdpr/Tcf2Service.java @@ -52,7 +52,7 @@ public Tcf2Service(GdprConfig gdprConfig, BidderCatalog bidderCatalog) { this.defaultPurposes = gdprConfig.getPurposes() == null ? Purposes.builder().build() : gdprConfig.getPurposes(); - this.defaultSpecialFeatures = ObjectUtils.defaultIfNull( + this.defaultSpecialFeatures = ObjectUtils.getIfNull( gdprConfig.getSpecialFeatures(), SpecialFeatures.builder().build()); this.purposeOneTreatmentInterpretation = gdprConfig.getPurposeOneTreatmentInterpretation(); diff --git a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListFileStore.java b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListFileStore.java index e02669c8e26..39876501ef3 100644 --- a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListFileStore.java +++ b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListFileStore.java @@ -6,6 +6,7 @@ import io.vertx.core.file.FileSystem; import io.vertx.core.file.FileSystemException; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.apache.commons.lang3.exception.ExceptionUtils; import org.prebid.server.exception.PreBidException; import org.prebid.server.json.JacksonMapper; @@ -92,7 +93,7 @@ Optional getLatestVendorListFromCache(String cacheDir) { private static Integer parseCachedFileVersion(String filepath) { final String filename = new File(filepath).getName(); - final String filenameWithoutExtension = StringUtils.removeEnd(filename, JSON_SUFFIX); + final String filenameWithoutExtension = Strings.CS.removeEnd(filename, JSON_SUFFIX); return Integer.valueOf(filenameWithoutExtension); } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/FlexibleExtension.java b/src/main/java/org/prebid/server/proto/openrtb/ext/FlexibleExtension.java index 4a33f49772f..d32c8eb0032 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/FlexibleExtension.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/FlexibleExtension.java @@ -42,4 +42,8 @@ public void addProperty(String key, JsonNode value) { public void addProperties(Map properties) { this.properties.putAll(properties); } + + public void removeProperty(String key) { + properties.remove(key); + } } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/DsaTransparency.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/DsaTransparency.java index 6b2e47bc623..4f0ab6db451 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/DsaTransparency.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/DsaTransparency.java @@ -7,20 +7,20 @@ /** * Defines the contract for bidrequest.regs.ext.dsa.transparency[i] - * and bidresponse.seatbid[i].bid[i].ext.dsa.transparency[i] + * and bidresponse.seatbid[i].bid[i].ext.dsa.transparency[i] */ @Value(staticConstructor = "of") public class DsaTransparency { /** * Defines the contract for bidrequest.regs.ext.dsa.transparency[i].domain - * and bidresponse.seatbid[i].bid[i].ext.dsa.transparency[i].domain + * and bidresponse.seatbid[i].bid[i].ext.dsa.transparency[i].domain */ String domain; /** * Defines the contract for bidrequest.regs.ext.dsa.transparency[i].dsaparams[] - * and bidresponse.seatbid[i].bid[i].ext.dsa.transparency[i].dsaparams[] + * and bidresponse.seatbid[i].bid[i].ext.dsa.transparency[i].dsaparams[] */ @JsonProperty("dsaparams") List dsaParams; diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ImpMediaType.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ImpMediaType.java index d619ed27e80..8c25ed9fbe9 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ImpMediaType.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ImpMediaType.java @@ -18,7 +18,7 @@ public enum ImpMediaType { public String toString() { return this == xNative ? "native" : this == video_outstream ? "video-outstream" - : this == video_instream ? "video-instream" - : super.toString(); + : this == video_instream ? "video-instream" + : super.toString(); } } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adagio/ExtImpAdagio.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adagio/ExtImpAdagio.java deleted file mode 100644 index fb8cc3ed7b6..00000000000 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adagio/ExtImpAdagio.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.prebid.server.proto.openrtb.ext.request.adagio; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Value; - -@Value(staticConstructor = "of") -public class ExtImpAdagio { - - @JsonProperty("organizationId") - String organizationId; - - String placement; - - String site; - - String pagetype; - - String category; -} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/adswag/ExtImpAdswag.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adswag/ExtImpAdswag.java new file mode 100644 index 00000000000..2de23e9340f --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/adswag/ExtImpAdswag.java @@ -0,0 +1,14 @@ +package org.prebid.server.proto.openrtb.ext.request.adswag; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Value; + +@Value(staticConstructor = "of") +public class ExtImpAdswag { + + @JsonProperty("publisherId") + String publisherId; + + @JsonProperty("placementId") + String placementId; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/aduptech/ExtImpAduptech.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/aduptech/ExtImpAduptech.java deleted file mode 100644 index 6e92ad45db7..00000000000 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/aduptech/ExtImpAduptech.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.prebid.server.proto.openrtb.ext.request.aduptech; - -import com.fasterxml.jackson.databind.node.ObjectNode; -import lombok.Value; - -@Value(staticConstructor = "of") -public class ExtImpAduptech { - - String publisher; - - String placement; - - String query; - - Boolean adtest; - - Boolean debug; - - ObjectNode ext; -} - diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/bidwave/ExtImpBidwave.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/bidwave/ExtImpBidwave.java new file mode 100644 index 00000000000..83d38e74702 --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/bidwave/ExtImpBidwave.java @@ -0,0 +1,11 @@ +package org.prebid.server.proto.openrtb.ext.request.bidwave; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Value; + +@Value(staticConstructor = "of") +public class ExtImpBidwave { + + @JsonProperty("publisherId") + String publisherId; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/connectad/ExtImpConnectAd.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connectad/ExtImpConnectAd.java index a75c4846f64..cb4e0badd21 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/connectad/ExtImpConnectAd.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connectad/ExtImpConnectAd.java @@ -9,10 +9,10 @@ public class ExtImpConnectAd { @JsonProperty("networkId") - String networkId; + Integer networkId; @JsonProperty("siteId") - String siteId; + Integer siteId; @JsonProperty("bidfloor") BigDecimal bidFloor; diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/eskimi/ExtImpEskimi.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/eskimi/ExtImpEskimi.java new file mode 100644 index 00000000000..32ac23cd004 --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/eskimi/ExtImpEskimi.java @@ -0,0 +1,28 @@ +package org.prebid.server.proto.openrtb.ext.request.eskimi; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Value; + +import java.math.BigDecimal; +import java.util.List; + +@Value(staticConstructor = "of") +public class ExtImpEskimi { + + @JsonProperty("placementId") + Integer placementId; + + @JsonProperty("bidFloor") + BigDecimal bidFloor; + + @JsonProperty("bidFloorCur") + String bidFloorCur; + + List bcat; + + List badv; + + List bapp; + + List battr; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/floxis/ExtImpFloxis.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/floxis/ExtImpFloxis.java new file mode 100644 index 00000000000..e1302852cde --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/floxis/ExtImpFloxis.java @@ -0,0 +1,13 @@ +package org.prebid.server.proto.openrtb.ext.request.floxis; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class ExtImpFloxis { + + String seat; + + String region; + + String partner; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/missena/ExtImpMissena.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/missena/ExtImpMissena.java index 0c3a8fd08ab..bf11d296186 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/missena/ExtImpMissena.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/missena/ExtImpMissena.java @@ -18,8 +18,7 @@ public class ExtImpMissena { String placement; - @JsonProperty("test") - String testMode; + String sample; ObjectNode settings; } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/nativo/ExtImpNativo.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/nativo/ExtImpNativo.java deleted file mode 100644 index 8dfb32333d7..00000000000 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/nativo/ExtImpNativo.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.prebid.server.proto.openrtb.ext.request.nativo; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Value; - -@Value(staticConstructor = "of") -public class ExtImpNativo { - - @JsonProperty("placementId") - Object placementId; -} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/scalibur/ExtImpScalibur.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/scalibur/ExtImpScalibur.java new file mode 100644 index 00000000000..38f7964df30 --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/scalibur/ExtImpScalibur.java @@ -0,0 +1,21 @@ +package org.prebid.server.proto.openrtb.ext.request.scalibur; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Value; + +import java.math.BigDecimal; + +@Value(staticConstructor = "of") +public class ExtImpScalibur { + + @JsonProperty("placementId") + String placementId; + + @JsonProperty("bidfloor") + BigDecimal bidFloor; + + @JsonProperty("bidfloorcur") + String bidFloorCur; + + String host; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/smartrtb/ExtRequestSmartrtb.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/smartrtb/ExtRequestSmartrtb.java deleted file mode 100644 index b38895aad9a..00000000000 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/smartrtb/ExtRequestSmartrtb.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.prebid.server.proto.openrtb.ext.request.smartrtb; - -import lombok.Value; - -@Value(staticConstructor = "of") -public class ExtRequestSmartrtb { - - String pubId; - - String zoneId; - - Boolean forceBid; -} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/sspbc/ExtImpSspbc.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/sspbc/ExtImpSspbc.java deleted file mode 100644 index 27f06a62fde..00000000000 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/sspbc/ExtImpSspbc.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.prebid.server.proto.openrtb.ext.request.sspbc; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Value; - -@Value(staticConstructor = "of") -public class ExtImpSspbc { - - @JsonProperty("siteId") - String siteId; - @JsonProperty("id") - String id; - @JsonProperty("test") - Integer test; -} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/synapsehx/ExtImpSynapseHX.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/synapsehx/ExtImpSynapseHX.java new file mode 100644 index 00000000000..83a9d08d9e5 --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/synapsehx/ExtImpSynapseHX.java @@ -0,0 +1,11 @@ +package org.prebid.server.proto.openrtb.ext.request.synapsehx; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Value; + +@Value(staticConstructor = "of") +public class ExtImpSynapseHX { + + @JsonProperty("tenantId") + String tenantId; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/BidType.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/BidType.java index 25c57328600..6ef50a43ce1 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/response/BidType.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/BidType.java @@ -1,7 +1,7 @@ package org.prebid.server.proto.openrtb.ext.response; import com.fasterxml.jackson.annotation.JsonProperty; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; public enum BidType { @@ -17,7 +17,7 @@ public String getName() { public static BidType fromString(String bidType) { try { - return StringUtils.equals(bidType, "native") ? xNative : valueOf(bidType); + return Strings.CS.equals(bidType, "native") ? xNative : valueOf(bidType); } catch (IllegalArgumentException e) { return null; } diff --git a/src/main/java/org/prebid/server/settings/FileApplicationSettings.java b/src/main/java/org/prebid/server/settings/FileApplicationSettings.java index b5930b0123f..5d001d771bb 100644 --- a/src/main/java/org/prebid/server/settings/FileApplicationSettings.java +++ b/src/main/java/org/prebid/server/settings/FileApplicationSettings.java @@ -8,6 +8,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.SetUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.timeout.Timeout; import org.prebid.server.json.DecodeException; @@ -103,7 +104,7 @@ private static Map readStoredData(FileSystem fileSystem, String return fileSystem.readDirBlocking(dir).stream() .filter(filepath -> filepath.endsWith(JSON_SUFFIX)) .collect(Collectors.toMap( - filepath -> StringUtils.removeEnd(new File(filepath).getName(), JSON_SUFFIX), + filepath -> Strings.CS.removeEnd(new File(filepath).getName(), JSON_SUFFIX), filepath -> fileSystem.readFileBlocking(filepath).toString())); } @@ -123,7 +124,7 @@ private static Map.Entry> readProfile(FileSystem fil String profileFilePath, JacksonMapper jacksonMapper) { - final String profileFileName = StringUtils.removeEnd(new File(profileFilePath).getName(), JSON_SUFFIX); + final String profileFileName = Strings.CS.removeEnd(new File(profileFilePath).getName(), JSON_SUFFIX); final String[] accountIdAndProfileId = profileFileName.split("-"); if (accountIdAndProfileId.length != 2) { throw new IllegalArgumentException("Invalid name of profile file: " + profileFileName); @@ -142,7 +143,7 @@ private static Map> readCategories(FileSystem file return fileSystem.readDirBlocking(dir).stream() .filter(filepath -> filepath.endsWith(JSON_SUFFIX)) .collect(Collectors.toMap( - filepath -> StringUtils.removeEnd(new File(filepath).getName(), JSON_SUFFIX), + filepath -> Strings.CS.removeEnd(new File(filepath).getName(), JSON_SUFFIX), filepath -> parseCategories(filepath, fileSystem.readFileBlocking(filepath), jacksonMapper))); } diff --git a/src/main/java/org/prebid/server/settings/S3ApplicationSettings.java b/src/main/java/org/prebid/server/settings/S3ApplicationSettings.java index c9b71c6e7ad..208b8881902 100644 --- a/src/main/java/org/prebid/server/settings/S3ApplicationSettings.java +++ b/src/main/java/org/prebid/server/settings/S3ApplicationSettings.java @@ -5,7 +5,7 @@ import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.apache.commons.collections4.SetUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.model.Tuple2; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.timeout.Timeout; @@ -94,7 +94,7 @@ private Account decodeAccount(String fileContent, String requestedAccountId) { private static void validateAccount(Account account, String requestedAccountId) { final String receivedAccountId = account != null ? account.getId() : null; - if (!StringUtils.equals(receivedAccountId, requestedAccountId)) { + if (!Strings.CS.equals(receivedAccountId, requestedAccountId)) { throw new PreBidException( "Account with id %s does not match id %s in file".formatted(requestedAccountId, receivedAccountId)); } diff --git a/src/main/java/org/prebid/server/settings/SettingsCache.java b/src/main/java/org/prebid/server/settings/SettingsCache.java index 1066d0a121c..f1a1688d068 100644 --- a/src/main/java/org/prebid/server/settings/SettingsCache.java +++ b/src/main/java/org/prebid/server/settings/SettingsCache.java @@ -68,7 +68,7 @@ private static void saveCachedValue(Map>> cache, String id, T value) { - final Set> values = ObjectUtils.defaultIfNull(cache.get(id), new HashSet<>()); + final Set> values = ObjectUtils.getIfNull(cache.get(id), new HashSet<>()); values.add(StoredItem.of(accountId, value)); cache.put(id, values); } diff --git a/src/main/java/org/prebid/server/settings/helper/ParametrizedQueryMySqlHelper.java b/src/main/java/org/prebid/server/settings/helper/ParametrizedQueryMySqlHelper.java index e492b1ce385..deb28b276fb 100644 --- a/src/main/java/org/prebid/server/settings/helper/ParametrizedQueryMySqlHelper.java +++ b/src/main/java/org/prebid/server/settings/helper/ParametrizedQueryMySqlHelper.java @@ -28,7 +28,7 @@ private static String parameterHolders(int paramsSize) { return paramsSize == 0 ? "NULL" : IntStream.range(0, paramsSize) - .mapToObj(i -> PARAMETER_PLACEHOLDER) - .collect(Collectors.joining(",")); + .mapToObj(i -> PARAMETER_PLACEHOLDER) + .collect(Collectors.joining(",")); } } diff --git a/src/main/java/org/prebid/server/settings/helper/ParametrizedQueryPostgresHelper.java b/src/main/java/org/prebid/server/settings/helper/ParametrizedQueryPostgresHelper.java index 69388e3423c..d4f5a79be95 100644 --- a/src/main/java/org/prebid/server/settings/helper/ParametrizedQueryPostgresHelper.java +++ b/src/main/java/org/prebid/server/settings/helper/ParametrizedQueryPostgresHelper.java @@ -40,7 +40,7 @@ private static String parameterHolders(int paramsSize, int start) { return paramsSize == 0 ? "NULL" : IntStream.range(start, start + paramsSize) - .mapToObj(i -> "\\$" + (i + 1)) - .collect(Collectors.joining(",")); + .mapToObj(i -> "\\$" + (i + 1)) + .collect(Collectors.joining(",")); } } diff --git a/src/main/java/org/prebid/server/settings/helper/StoredResponseFetcher.java b/src/main/java/org/prebid/server/settings/helper/StoredResponseFetcher.java deleted file mode 100644 index 3092841b06e..00000000000 --- a/src/main/java/org/prebid/server/settings/helper/StoredResponseFetcher.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.prebid.server.settings.helper; - -import io.vertx.core.Future; -import org.prebid.server.execution.timeout.Timeout; -import org.prebid.server.settings.model.StoredResponseDataResult; - -import java.util.Set; - -@FunctionalInterface -public interface StoredResponseFetcher { - - Future apply(Set responseIds, Timeout timeout); -} diff --git a/src/main/java/org/prebid/server/settings/model/AccountAuctionEventConfig.java b/src/main/java/org/prebid/server/settings/model/AccountAuctionEventConfig.java index 3df397c63f8..4d737041940 100644 --- a/src/main/java/org/prebid/server/settings/model/AccountAuctionEventConfig.java +++ b/src/main/java/org/prebid/server/settings/model/AccountAuctionEventConfig.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonAnySetter; import lombok.Builder; import lombok.Value; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import java.util.Collections; import java.util.HashMap; @@ -27,7 +27,7 @@ public void addEvent(String key, Boolean value) { } private static String resolveKey(String key) { - if (StringUtils.equalsIgnoreCase("pbjs", key)) { + if (Strings.CI.equals("pbjs", key)) { return "web"; } diff --git a/src/main/java/org/prebid/server/settings/service/DatabasePeriodicRefreshService.java b/src/main/java/org/prebid/server/settings/service/DatabasePeriodicRefreshService.java index 9ace90196c2..6cec71e5d9b 100644 --- a/src/main/java/org/prebid/server/settings/service/DatabasePeriodicRefreshService.java +++ b/src/main/java/org/prebid/server/settings/service/DatabasePeriodicRefreshService.java @@ -3,6 +3,7 @@ import io.vertx.core.Future; import io.vertx.core.Vertx; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.execution.timeout.Timeout; import org.prebid.server.execution.timeout.TimeoutFactory; import org.prebid.server.log.Logger; @@ -178,7 +179,7 @@ private StoredDataResult invalidate(StoredDataResult storedDataR private static List getInvalidatedKeys(Map changesMap) { return changesMap.entrySet().stream() .filter(entry -> StringUtils.isBlank(entry.getValue()) - || StringUtils.equalsIgnoreCase(entry.getValue(), "null")) + || Strings.CI.equals(entry.getValue(), "null")) .map(Map.Entry::getKey) .toList(); } diff --git a/src/main/java/org/prebid/server/spring/config/GeoLocationConfiguration.java b/src/main/java/org/prebid/server/spring/config/GeoLocationConfiguration.java index 3950021f6c0..5df699c5398 100644 --- a/src/main/java/org/prebid/server/spring/config/GeoLocationConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/GeoLocationConfiguration.java @@ -116,19 +116,19 @@ private static org.prebid.server.geolocation.model.GeoInfoConfiguration from( config.getAddressPattern(), geoInfo != null ? org.prebid.server.geolocation.model.GeoInfo.builder() - .vendor(StringUtils.EMPTY) - .continent(geoInfo.getContinent()) - .country(geoInfo.getCountry()) - .region(geoInfo.getRegion()) - .city(geoInfo.getCity()) - .metroGoogle(geoInfo.getMetroGoogle()) - .metroNielsen(geoInfo.getMetroNielsen()) - .zip(geoInfo.getZip()) - .connectionSpeed(geoInfo.getConnectionSpeed()) - .lat(geoInfo.getLat()) - .lon(geoInfo.getLon()) - .timeZone(geoInfo.getTimeZone()) - .build() + .vendor(StringUtils.EMPTY) + .continent(geoInfo.getContinent()) + .country(geoInfo.getCountry()) + .region(geoInfo.getRegion()) + .city(geoInfo.getCity()) + .metroGoogle(geoInfo.getMetroGoogle()) + .metroNielsen(geoInfo.getMetroNielsen()) + .zip(geoInfo.getZip()) + .connectionSpeed(geoInfo.getConnectionSpeed()) + .lat(geoInfo.getLat()) + .lon(geoInfo.getLon()) + .timeZone(geoInfo.getTimeZone()) + .build() : null); } diff --git a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java index d2146333737..8bc67800f0b 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -772,7 +772,7 @@ CookieSyncService cookieSyncService( return new CookieSyncService( defaultLimit, - ObjectUtils.defaultIfNull(maxLimit, Integer.MAX_VALUE), + ObjectUtils.getIfNull(maxLimit, Integer.MAX_VALUE), bidderCatalog, hostVendorTcfDefinerService, ccpaEnforcement, diff --git a/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java b/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java index be937e1bb44..557ab5ab4e9 100644 --- a/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java @@ -468,7 +468,7 @@ static class ApplicationSettingsConfiguration { ApplicationSettings applicationSettings( @Autowired(required = false) CachingApplicationSettings cachingApplicationSettings, EnrichingApplicationSettings enrichingApplicationSettings) { - return ObjectUtils.defaultIfNull(cachingApplicationSettings, enrichingApplicationSettings); + return ObjectUtils.getIfNull(cachingApplicationSettings, enrichingApplicationSettings); } } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/AdswagConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/AdswagConfiguration.java new file mode 100644 index 00000000000..4a6e4d5bc53 --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/AdswagConfiguration.java @@ -0,0 +1,35 @@ +package org.prebid.server.spring.config.bidder; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.adswag.AdswagBidder; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; +import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/adswag.yaml", factory = YamlPropertySourceFactory.class) +public class AdswagConfiguration { + + private static final String BIDDER_NAME = "adswag"; + + @Bean("adswagConfigurationProperties") + @ConfigurationProperties("adapters.adswag") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps adswagBidderDeps(BidderConfigurationProperties adswagConfigurationProperties, + JacksonMapper mapper) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(adswagConfigurationProperties) + .bidderCreator(config -> new AdswagBidder(config.getEndpoint(), mapper)) + .assemble(); + } +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/AutomatadBidderConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/AutomatadBidderConfiguration.java index 345106fc79f..196793206f6 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/AutomatadBidderConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/AutomatadBidderConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps automatadBidderDeps(BidderConfigurationProperties automatadConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(automatadConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/BeopConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/BeopConfiguration.java index f1df84df63a..b8df421c08c 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/BeopConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/BeopConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps beopBidderDeps(BidderConfigurationProperties beopConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(beopConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/BidwaveConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/BidwaveConfiguration.java new file mode 100644 index 00000000000..5a49fc29ea6 --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/BidwaveConfiguration.java @@ -0,0 +1,37 @@ +package org.prebid.server.spring.config.bidder; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.bidwave.BidwaveBidder; +import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; +import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/bidwave.yaml", factory = YamlPropertySourceFactory.class) +public class BidwaveConfiguration { + + private static final String BIDDER_NAME = "bidwave"; + + @Bean("bidwaveConfigurationProperties") + @ConfigurationProperties("adapters.bidwave") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps bidwaveBidderDeps(BidderConfigurationProperties bidwaveConfigurationProperties, + CurrencyConversionService currencyConversionService, + JacksonMapper mapper) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(bidwaveConfigurationProperties) + .bidderCreator(config -> new BidwaveBidder(config.getEndpoint(), currencyConversionService, mapper)) + .assemble(); + } +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/DefineMediaConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/DefineMediaConfiguration.java index 393e3a25eba..645a9ef82ad 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/DefineMediaConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/DefineMediaConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps definemediaBidderDeps(BidderConfigurationProperties definemediaConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(definemediaConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/EskimiConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/EskimiConfiguration.java new file mode 100644 index 00000000000..d484bf70a8d --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/EskimiConfiguration.java @@ -0,0 +1,35 @@ +package org.prebid.server.spring.config.bidder; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.eskimi.EskimiBidder; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; +import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/eskimi.yaml", factory = YamlPropertySourceFactory.class) +public class EskimiConfiguration { + + private static final String BIDDER_NAME = "eskimi"; + + @Bean("eskimiConfigurationProperties") + @ConfigurationProperties("adapters.eskimi") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps eskimiBidderDeps(BidderConfigurationProperties eskimiConfigurationProperties, + JacksonMapper mapper) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(eskimiConfigurationProperties) + .bidderCreator(config -> new EskimiBidder(config.getEndpoint(), mapper)) + .assemble(); + } +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/FloxisConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/FloxisConfiguration.java new file mode 100644 index 00000000000..896ac465fbe --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/FloxisConfiguration.java @@ -0,0 +1,35 @@ +package org.prebid.server.spring.config.bidder; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.floxis.FloxisBidder; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; +import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/floxis.yaml", factory = YamlPropertySourceFactory.class) +public class FloxisConfiguration { + + private static final String BIDDER_NAME = "floxis"; + + @Bean("floxisConfigurationProperties") + @ConfigurationProperties("adapters.floxis") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps floxisBidderDeps(BidderConfigurationProperties floxisConfigurationProperties, + JacksonMapper mapper) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(floxisConfigurationProperties) + .bidderCreator(config -> new FloxisBidder(config.getEndpoint(), mapper)) + .assemble(); + } +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/LemmaDigitalConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/LemmaDigitalConfiguration.java index e3f9920f7c2..ef8f16d56f0 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/LemmaDigitalConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/LemmaDigitalConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps lemmadigitalBidderDeps(BidderConfigurationProperties lemmaDigitalConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(lemmaDigitalConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/MotorikConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/MotorikConfiguration.java index be60762aeeb..6ee077a2d26 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/MotorikConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/MotorikConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps motorikBidderDeps(BidderConfigurationProperties motorikConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(motorikConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/OguryConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/OguryConfiguration.java index ef1829c05a6..4206b46f710 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/OguryConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/OguryConfiguration.java @@ -26,8 +26,8 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps oguryBidderDeps(BidderConfigurationProperties oguryConfigurationProperties, - CurrencyConversionService currencyConversionService, - JacksonMapper mapper) { + CurrencyConversionService currencyConversionService, + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(oguryConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/OwnAdxBidderConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/OwnAdxBidderConfiguration.java index c7d47a8eabc..e50e7edaedf 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/OwnAdxBidderConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/OwnAdxBidderConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps ownAdxBidderDeps(BidderConfigurationProperties ownAdxConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(ownAdxConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/PrecisoConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/PrecisoConfiguration.java index 615215e6e71..fe1a959c898 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/PrecisoConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/PrecisoConfiguration.java @@ -26,8 +26,9 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps precisoBidderDeps(BidderConfigurationProperties precisoConfigurationProperties, - CurrencyConversionService currencyConversionService, - JacksonMapper mapper) { + CurrencyConversionService currencyConversionService, + JacksonMapper mapper) { + return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(precisoConfigurationProperties) .bidderCreator(config -> new PrecisoBidder( diff --git a/src/main/java/org/prebid/server/spring/config/bidder/PwbidConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/PwbidConfiguration.java index 8c188190d12..7f6d678223e 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/PwbidConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/PwbidConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps pwbidBidderDeps(BidderConfigurationProperties pwbidConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(pwbidConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/RoulaxConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/RoulaxConfiguration.java index c623f4ca72d..21835668ee7 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/RoulaxConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/RoulaxConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps roulaxBidderDeps(BidderConfigurationProperties roulaxConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(roulaxConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/RtbhouseConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/RtbhouseConfiguration.java index 8d421e41229..729ef3fad22 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/RtbhouseConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/RtbhouseConfiguration.java @@ -31,9 +31,9 @@ BidderDeps rtbhouseBidderDeps(BidderConfigurationProperties rtbhouseConfiguratio return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(rtbhouseConfigurationProperties) .bidderCreator(config -> new RtbhouseBidder( - config.getEndpoint(), - currencyConversionService, - mapper)) + config.getEndpoint(), + currencyConversionService, + mapper)) .assemble(); } } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/ScaliburConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/ScaliburConfiguration.java new file mode 100644 index 00000000000..4e69427e3ef --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/ScaliburConfiguration.java @@ -0,0 +1,37 @@ +package org.prebid.server.spring.config.bidder; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.scalibur.ScaliburBidder; +import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; +import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/scalibur.yaml", factory = YamlPropertySourceFactory.class) +public class ScaliburConfiguration { + + private static final String BIDDER_NAME = "scalibur"; + + @Bean("scaliburConfigurationProperties") + @ConfigurationProperties("adapters.scalibur") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps scaliburBidderDeps(BidderConfigurationProperties scaliburConfigurationProperties, + CurrencyConversionService currencyConversionService, + JacksonMapper mapper) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(scaliburConfigurationProperties) + .bidderCreator(config -> new ScaliburBidder(config.getEndpoint(), currencyConversionService, mapper)) + .assemble(); + } +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/ScreencoreConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/ScreencoreConfiguration.java index 7699029941a..5c2b97035e1 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/ScreencoreConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/ScreencoreConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps screencoreBidderDeps(BidderConfigurationProperties screencoreConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(screencoreConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/SevioConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/SevioConfiguration.java new file mode 100644 index 00000000000..190886a4d3e --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/SevioConfiguration.java @@ -0,0 +1,34 @@ +package org.prebid.server.spring.config.bidder; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.sevio.SevioBidder; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; +import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/sevio.yaml", factory = YamlPropertySourceFactory.class) +public class SevioConfiguration { + + private static final String BIDDER_NAME = "sevio"; + + @Bean("sevioConfigurationProperties") + @ConfigurationProperties("adapters.sevio") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps sevioBidderDeps(BidderConfigurationProperties sevioConfigurationProperties, JacksonMapper mapper) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(sevioConfigurationProperties) + .bidderCreator(config -> new SevioBidder(config.getEndpoint(), mapper)) + .assemble(); + } +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/SmrtconnectConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/SmrtconnectConfiguration.java index 8f797a92038..b0d2f043786 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/SmrtconnectConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/SmrtconnectConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps smrtconnectBidderDeps(BidderConfigurationProperties smrtconnectConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(smrtconnectConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/SynapseHXBidderConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/SynapseHXBidderConfiguration.java new file mode 100644 index 00000000000..c9745d20818 --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/SynapseHXBidderConfiguration.java @@ -0,0 +1,35 @@ +package org.prebid.server.spring.config.bidder; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.synapsehx.SynapseHXBidder; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; +import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/synapsehx.yaml", factory = YamlPropertySourceFactory.class) +public class SynapseHXBidderConfiguration { + + private static final String BIDDER_NAME = "synapsehx"; + + @Bean("synapsehxConfigurationProperties") + @ConfigurationProperties("adapters.synapsehx") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps synapsehxBidderDeps(BidderConfigurationProperties synapsehxConfigurationProperties, + JacksonMapper mapper) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(synapsehxConfigurationProperties) + .bidderCreator(config -> new SynapseHXBidder(config.getEndpoint(), mapper)) + .assemble(); + } +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/TpmnAdnBidderConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/TpmnAdnBidderConfiguration.java index 9006119fc6c..665db3730d0 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/TpmnAdnBidderConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/TpmnAdnBidderConfiguration.java @@ -26,8 +26,8 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps tpmnBidderDeps(BidderConfigurationProperties tpmnConfigurationProperties, - CurrencyConversionService currencyConversionService, - JacksonMapper mapper) { + CurrencyConversionService currencyConversionService, + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(tpmnConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/TrafficGateConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/TrafficGateConfiguration.java index c13d84282fc..ae735c0a612 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/TrafficGateConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/TrafficGateConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps trafficGateBidderDeps(BidderConfigurationProperties trafficGateConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(trafficGateConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/VidazooConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/VidazooConfiguration.java index 9366e7d991b..d9123a7b0f6 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/VidazooConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/VidazooConfiguration.java @@ -28,8 +28,8 @@ BidderDeps vidazooBidderDeps(BidderConfigurationProperties vidazooConfigurationP JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) - .withConfig(vidazooConfigurationProperties) - .bidderCreator(config -> new VidazooBidder(config.getEndpoint(), mapper)) - .assemble(); + .withConfig(vidazooConfigurationProperties) + .bidderCreator(config -> new VidazooBidder(config.getEndpoint(), mapper)) + .assemble(); } } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/YahooAdsConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/YahooAdsConfiguration.java index 78a857edcd1..0be607ce024 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/YahooAdsConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/YahooAdsConfiguration.java @@ -1,6 +1,5 @@ package org.prebid.server.spring.config.bidder; -import org.prebid.server.auction.versionconverter.BidRequestOrtbVersionConversionManager; import org.prebid.server.bidder.BidderDeps; import org.prebid.server.bidder.yahooads.YahooAdsBidder; import org.prebid.server.json.JacksonMapper; @@ -26,12 +25,11 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps yahooAdsBidderDeps(BidderConfigurationProperties yahooAdsConfigurationProperties, - JacksonMapper mapper, - BidRequestOrtbVersionConversionManager conversionManager) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(yahooAdsConfigurationProperties) - .bidderCreator(config -> new YahooAdsBidder(config.getEndpoint(), conversionManager, mapper)) + .bidderCreator(config -> new YahooAdsBidder(config.getEndpoint(), mapper)) .assemble(); } } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/YearxeroConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/YearxeroConfiguration.java index 3f8c327a1df..0339b98ed41 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/YearxeroConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/YearxeroConfiguration.java @@ -25,7 +25,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps yearxeroBidderDeps(BidderConfigurationProperties yearxeroConfigurationProperties, - JacksonMapper mapper) { + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(yearxeroConfigurationProperties) diff --git a/src/main/java/org/prebid/server/spring/config/bidder/model/BidderConfigurationProperties.java b/src/main/java/org/prebid/server/spring/config/bidder/model/BidderConfigurationProperties.java index a13e1aef3ec..953c7f537f1 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/model/BidderConfigurationProperties.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/model/BidderConfigurationProperties.java @@ -61,15 +61,15 @@ public BidderConfigurationProperties() { @PostConstruct private void init() { - enabled = ObjectUtils.defaultIfNull(enabled, defaultProperties.getEnabled()); - ortbVersion = ObjectUtils.defaultIfNull(ortbVersion, defaultProperties.getOrtbVersion()); - pbsEnforcesCcpa = ObjectUtils.defaultIfNull(pbsEnforcesCcpa, defaultProperties.getPbsEnforcesCcpa()); - modifyingVastXmlAllowed = ObjectUtils.defaultIfNull( + enabled = ObjectUtils.getIfNull(enabled, defaultProperties.getEnabled()); + ortbVersion = ObjectUtils.getIfNull(ortbVersion, defaultProperties.getOrtbVersion()); + pbsEnforcesCcpa = ObjectUtils.getIfNull(pbsEnforcesCcpa, defaultProperties.getPbsEnforcesCcpa()); + modifyingVastXmlAllowed = ObjectUtils.getIfNull( modifyingVastXmlAllowed, defaultProperties.getModifyingVastXmlAllowed()); - debug = ObjectUtils.defaultIfNull(debug, defaultProperties.getDebug()); - aliases = ObjectUtils.defaultIfNull(aliases, defaultProperties.getAliases()); - deprecatedNames = ObjectUtils.defaultIfNull(deprecatedNames, defaultProperties.getDeprecatedNames()); - endpointCompression = ObjectUtils.defaultIfNull( + debug = ObjectUtils.getIfNull(debug, defaultProperties.getDebug()); + aliases = ObjectUtils.getIfNull(aliases, defaultProperties.getAliases()); + deprecatedNames = ObjectUtils.getIfNull(deprecatedNames, defaultProperties.getDeprecatedNames()); + endpointCompression = ObjectUtils.getIfNull( endpointCompression, defaultProperties.getEndpointCompression()); ortb = ortb != null && ortb.getMultiFormatSupported() != null ? ortb diff --git a/src/main/java/org/prebid/server/spring/config/metrics/MetricsConfiguration.java b/src/main/java/org/prebid/server/spring/config/metrics/MetricsConfiguration.java index a30b61f9fdd..638b053b4f9 100644 --- a/src/main/java/org/prebid/server/spring/config/metrics/MetricsConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/metrics/MetricsConfiguration.java @@ -72,7 +72,7 @@ ScheduledReporter influxdbReporter(InfluxdbProperties influxdbProperties, Metric influxdbProperties.getConnectTimeout(), influxdbProperties.getReadTimeout(), influxdbProperties.getPrefix()); - final Map tags = ObjectUtils.defaultIfNull( + final Map tags = ObjectUtils.getIfNull( influxdbProperties.getTags(), Collections.emptyMap() ); diff --git a/src/main/java/org/prebid/server/spring/config/server/admin/AdminEndpointsConfiguration.java b/src/main/java/org/prebid/server/spring/config/server/admin/AdminEndpointsConfiguration.java index a5938aab396..fafea52b6d2 100644 --- a/src/main/java/org/prebid/server/spring/config/server/admin/AdminEndpointsConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/server/admin/AdminEndpointsConfiguration.java @@ -205,7 +205,7 @@ AdminResourcesBinder adminPortAdminResourcesBinder(Map adminEndp @Bean Map adminEndpointCredentials(@Autowired(required = false) AdminEndpointCredentials credentials) { - return ObjectUtils.defaultIfNull(credentials.getCredentials(), Collections.emptyMap()); + return ObjectUtils.getIfNull(credentials.getCredentials(), Collections.emptyMap()); } @Component diff --git a/src/main/java/org/prebid/server/spring/config/server/admin/AdminServerAuthProvider.java b/src/main/java/org/prebid/server/spring/config/server/admin/AdminServerAuthProvider.java index 6796f7e13f6..8a369bceb01 100644 --- a/src/main/java/org/prebid/server/spring/config/server/admin/AdminServerAuthProvider.java +++ b/src/main/java/org/prebid/server/spring/config/server/admin/AdminServerAuthProvider.java @@ -7,6 +7,7 @@ import io.vertx.ext.auth.authentication.Credentials; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import java.util.Map; @@ -29,7 +30,7 @@ public Future authenticate(Credentials userCredentials) { final String requestPassword = StringUtils.chomp(principal.getString("password")); final String storedPassword = credentials.get(requestUsername); - return StringUtils.isNotBlank(requestPassword) && StringUtils.equals(storedPassword, requestPassword) + return StringUtils.isNotBlank(requestPassword) && Strings.CS.equals(storedPassword, requestPassword) ? Future.succeededFuture() : Future.failedFuture("Password does not match."); } diff --git a/src/main/java/org/prebid/server/util/BidderUtil.java b/src/main/java/org/prebid/server/util/BidderUtil.java index 21755842d2a..b86004f8383 100644 --- a/src/main/java/org/prebid/server/util/BidderUtil.java +++ b/src/main/java/org/prebid/server/util/BidderUtil.java @@ -7,6 +7,7 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.bidder.model.HttpRequest; import org.prebid.server.bidder.model.Price; import org.prebid.server.bidder.model.PriceFloorInfo; @@ -63,7 +64,7 @@ public static boolean isValidPrice(Price price) { public static boolean shouldConvertBidFloor(Price price, String bidderCurrency) { return isValidPrice(price) - && !StringUtils.equalsIgnoreCase(price.getCurrency(), bidderCurrency); + && !Strings.CI.equals(price.getCurrency(), bidderCurrency); } public static PriceFloorInfo resolvePriceFloor(Bid bid, BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/util/HttpUtil.java b/src/main/java/org/prebid/server/util/HttpUtil.java index a9468c97706..58a5f4bcb09 100644 --- a/src/main/java/org/prebid/server/util/HttpUtil.java +++ b/src/main/java/org/prebid/server/util/HttpUtil.java @@ -189,13 +189,13 @@ public static boolean executeSafely(RoutingContext routingContext, public static Map> toDebugHeaders(MultiMap headers) { return headers != null ? headers.entries().stream() - .filter(entry -> !isSensitiveHeader(entry.getKey())) - .collect(Collectors.toMap(Map.Entry::getKey, - entry -> StringUtils.isNotBlank(entry.getValue()) - ? Arrays.stream(entry.getValue().split(",")) - .map(String::trim) - .toList() - : Collections.singletonList(entry.getValue()))) + .filter(entry -> !isSensitiveHeader(entry.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, + entry -> StringUtils.isNotBlank(entry.getValue()) + ? Arrays.stream(entry.getValue().split(",")) + .map(String::trim) + .toList() + : Collections.singletonList(entry.getValue()))) : null; } diff --git a/src/main/java/org/prebid/server/validation/ImpValidator.java b/src/main/java/org/prebid/server/validation/ImpValidator.java index c254ac00bfc..7462b1ab3d3 100644 --- a/src/main/java/org/prebid/server/validation/ImpValidator.java +++ b/src/main/java/org/prebid/server/validation/ImpValidator.java @@ -647,8 +647,8 @@ private void validateMetrics(List metrics, String msgPrefix) throws Vali } final Float value = metric.getValue(); - if (value == null || value < 0.0 || value > 1.0) { - throw new ValidationException("%s.metric[%d].value must be in the range [0.0, 1.0]", msgPrefix, i); + if (value == null) { + throw new ValidationException("Missing %s.metric[%d].value", msgPrefix, i); } } } diff --git a/src/main/java/org/prebid/server/validation/RequestValidator.java b/src/main/java/org/prebid/server/validation/RequestValidator.java index b7cbb98d775..c2892323052 100644 --- a/src/main/java/org/prebid/server/validation/RequestValidator.java +++ b/src/main/java/org/prebid/server/validation/RequestValidator.java @@ -142,7 +142,7 @@ public ValidationResult validate(Account account, validateAliasesGvlIds(extRequestPrebid, aliases); validateAlternateBidderCodes(extRequestPrebid.getAlternateBidderCodes(), aliases); - final AlternateBidderCodesConfig alternateBidderCodesConfig = ObjectUtils.defaultIfNull( + final AlternateBidderCodesConfig alternateBidderCodesConfig = ObjectUtils.getIfNull( extRequestPrebid.getAlternateBidderCodes(), account == null ? null : account.getAlternateBidderCodes()); diff --git a/src/main/java/org/prebid/server/validation/ResponseBidValidator.java b/src/main/java/org/prebid/server/validation/ResponseBidValidator.java index 660d5785395..5cd4821ed42 100644 --- a/src/main/java/org/prebid/server/validation/ResponseBidValidator.java +++ b/src/main/java/org/prebid/server/validation/ResponseBidValidator.java @@ -9,11 +9,12 @@ import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.auction.aliases.BidderAliases; import org.prebid.server.auction.model.AuctionContext; +import org.prebid.server.auction.model.BidRejection; import org.prebid.server.auction.model.BidRejectionReason; import org.prebid.server.auction.model.BidRejectionTracker; -import org.prebid.server.auction.model.BidRejection; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.log.ConditionalLogger; import org.prebid.server.log.Logger; @@ -161,7 +162,7 @@ private void validateSeat(BidderBid bid, final String seat = bid.getSeat(); if (seat != null - && !StringUtils.equalsIgnoreCase(bidder, seat) + && !Strings.CI.equals(bidder, seat) && !bidderAliases.isAllowedAlternateBidderCode(bidder, seat)) { final String message = "invalid bidder code %s was set by the adapter %s for the account %s" @@ -235,7 +236,7 @@ private BidValidationEnforcement effectiveBannerMaxSizeEnforcement(Account accou final BidValidationEnforcement accountBannerMaxSizeEnforcement = validationConfig != null ? validationConfig.getBannerMaxSizeEnforcement() : null; - return ObjectUtils.defaultIfNull(accountBannerMaxSizeEnforcement, bannerMaxSizeEnforcement); + return ObjectUtils.getIfNull(accountBannerMaxSizeEnforcement, bannerMaxSizeEnforcement); } private static Format maxSizeForBanner(Imp imp) { @@ -303,8 +304,8 @@ private static boolean isImpSecure(Imp imp) { } private static boolean markupIsNotSecure(String adm) { - return StringUtils.containsAny(adm, INSECURE_MARKUP_MARKERS) - || !StringUtils.containsAny(adm, SECURE_MARKUP_MARKERS); + return Strings.CS.containsAny(adm, INSECURE_MARKUP_MARKERS) + || !Strings.CS.containsAny(adm, SECURE_MARKUP_MARKERS); } private List singleWarningOrValidationException( diff --git a/src/main/java/org/prebid/server/vertx/http/ParametrizedDecompressionHandler.java b/src/main/java/org/prebid/server/vertx/http/ParametrizedDecompressionHandler.java index 20af702492f..c7f80f937da 100644 --- a/src/main/java/org/prebid/server/vertx/http/ParametrizedDecompressionHandler.java +++ b/src/main/java/org/prebid/server/vertx/http/ParametrizedDecompressionHandler.java @@ -5,7 +5,7 @@ import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.impl.RoutingContextInternal; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -26,7 +26,7 @@ public ParametrizedDecompressionHandler(int maxBodySize) { @Override public void handle(RoutingContext routingContext) { - if (!StringUtils.equalsAny(routingContext.request().getParam("gzip"), "1", "true")) { + if (!Strings.CS.equalsAny(routingContext.request().getParam("gzip"), "1", "true")) { routingContext.next(); return; } diff --git a/src/main/resources/bidder-config/adagio.yaml b/src/main/resources/bidder-config/adagio.yaml index 9848b3135f2..62915cf545b 100644 --- a/src/main/resources/bidder-config/adagio.yaml +++ b/src/main/resources/bidder-config/adagio.yaml @@ -23,5 +23,5 @@ adapters: usersync: cookie-family-name: adagio iframe: - url: https://u-REGION.4dex.io/pbserver/usync.html?gdpr={gdpr}&gdpr_consent={gdpr_consent}&us_privacy={us_privacy}&gpp={gpp}&&gpp_sid={gpp_sid}&r={redirect_url} + url: https://u-REGION.4dex.io/pbserver/usync.html?gdpr={gdpr}&gdpr_consent={gdpr_consent}&us_privacy={us_privacy}&gpp={gpp}&gpp_sid={gpp_sid}&r={redirect_url} uid-macro: '{UID}' diff --git a/src/main/resources/bidder-config/adswag.yaml b/src/main/resources/bidder-config/adswag.yaml new file mode 100644 index 00000000000..0f40b19e4d2 --- /dev/null +++ b/src/main/resources/bidder-config/adswag.yaml @@ -0,0 +1,26 @@ +adapters: + adswag: + ortb-version: "2.6" + endpoint: https://bid.adswag.ai/prebid/bid + modifying-vast-xml-allowed: false + geoscope: + - EEA + ortb: + multiformat-supported: true + usersync: + cookie-family-name: adswag + redirect: + url: https://ev.adswag.ai/sync/pixel?gdpr={gdpr}&gdpr_consent={gdpr_consent}&us_privacy={us_privacy}&gpp={gpp}&gpp_sid={gpp_sid}&redirect={redirect_url} + uid-macro: '$UID' + meta-info: + maintainer-email: prebid@adswag.ai + app-media-types: + - banner + - video + - audio + site-media-types: + - banner + - video + - audio + supported-vendors: + vendor-id: 1417 diff --git a/src/main/resources/bidder-config/adverxo.yaml b/src/main/resources/bidder-config/adverxo.yaml index 988897fcddc..a3f05b144ad 100644 --- a/src/main/resources/bidder-config/adverxo.yaml +++ b/src/main/resources/bidder-config/adverxo.yaml @@ -43,7 +43,7 @@ adapters: url: https://hmidssp.com/usync?type=iframe&gdpr={gdpr}&consent={gdpr_consent}&us_privacy={us_privacy}&redirect={redirect_url} uid-macro: '$UID' redirect: - url: https://hmidssp.com/usync?type=image&gdpr={gdpr}&consent={gdpr_consent}&us_privacy={us_privacy}&redirect={redirect_url} + url: https://hmidssp.com/usync?type=image&gdpr={gdpr}&consent={gdpr_consent}&us_privacy={us_privacy}&redirect={redirect_url} uid-macro: '$UID' meta-info: maintainer-email: developer@adverxo.com diff --git a/src/main/resources/bidder-config/beop.yaml b/src/main/resources/bidder-config/beop.yaml index c71eac10157..952f2d05d05 100644 --- a/src/main/resources/bidder-config/beop.yaml +++ b/src/main/resources/bidder-config/beop.yaml @@ -10,5 +10,5 @@ adapters: site-media-types: - banner - video - supported-vendors: [] + supported-vendors: [ ] vendor-id: 666 diff --git a/src/main/resources/bidder-config/bidwave.yaml b/src/main/resources/bidder-config/bidwave.yaml new file mode 100644 index 00000000000..65bd02fb891 --- /dev/null +++ b/src/main/resources/bidder-config/bidwave.yaml @@ -0,0 +1,14 @@ +adapters: + bidwave: + endpoint: https://rtb.bidwave.net/rtb/v1/bid + ortb-version: "2.6" + meta-info: + maintainer-email: prebid@bidwave.net + app-media-types: + - banner + - video + site-media-types: + - banner + - video + supported-vendors: + vendor-id: 0 diff --git a/src/main/resources/bidder-config/connectad.yaml b/src/main/resources/bidder-config/connectad.yaml index d6f9db7301a..26d10dc57ed 100644 --- a/src/main/resources/bidder-config/connectad.yaml +++ b/src/main/resources/bidder-config/connectad.yaml @@ -2,18 +2,25 @@ adapters: connectad: # Please uncomment the appropriate endpoint URL for your datacenter # Europe - endpoint: "http://bidder.connectad.io/API?src=pbs" + endpoint: "https://bidder.connectad.io/API?src=pbs" + ortb-version: "2.6" # North/South America - # endpoint: "http://bidder-us.connectad.io/API?src=pbs" + # endpoint: "https://bidder-us.connectad.io/API?src=pbs" # APAC - # endpoint: "http://bidder-apac.connectad.io/API?src=pbs" + # endpoint: "https://bidder-apac.connectad.io/API?src=pbs" endpoint-compression: gzip meta-info: maintainer-email: support@connectad.io app-media-types: - banner + - video + - native + - audio site-media-types: - banner + - video + - native + - audio supported-vendors: vendor-id: 138 usersync: diff --git a/src/main/resources/bidder-config/eskimi.yaml b/src/main/resources/bidder-config/eskimi.yaml new file mode 100644 index 00000000000..cfdd1d612db --- /dev/null +++ b/src/main/resources/bidder-config/eskimi.yaml @@ -0,0 +1,20 @@ +adapters: + eskimi: + endpoint: https://ittr.eskimi.com/prebidjs + modifying-vast-xml-allowed: false + ortb-version: "2.6" + meta-info: + maintainer-email: prebid@eskimi.com + app-media-types: + - banner + - video + site-media-types: + - banner + - video + supported-vendors: + vendor-id: 814 + usersync: + cookie-family-name: eskimi + redirect: + url: https://ittpx.eskimi.com/sync?sp_id=137&gdpr={gdpr}&gdpr_consent={gdpr_consent}&us_privacy={us_privacy}&gpp={gpp}&gpp_sid={gpp_sid}&dest={redirect_url} + user-macro: '${USER_ID}' diff --git a/src/main/resources/bidder-config/floxis.yaml b/src/main/resources/bidder-config/floxis.yaml new file mode 100644 index 00000000000..a2f058c5e14 --- /dev/null +++ b/src/main/resources/bidder-config/floxis.yaml @@ -0,0 +1,25 @@ +adapters: + floxis: + endpoint: https://{Host}.floxis.tech/pbs?seat={SeatId} + endpoint-compression: gzip + ortb-version: "2.6" + modifying-vast-xml-allowed: false + meta-info: + maintainer-email: prebid@floxis.tech + app-media-types: + - banner + - video + - native + - audio + site-media-types: + - banner + - video + - native + - audio + supported-vendors: + vendor-id: 1609 + usersync: + cookie-family-name: floxis + redirect: + url: "https://px-us-e.floxis.tech/sync?gdpr={gdpr}&gdpr_consent={gdpr_consent}&gpp={gpp}&gpp_sid={gpp_sid}&us_privacy={us_privacy}&dest={redirect_url}" + uid-macro: "${USER_ID}" diff --git a/src/main/resources/bidder-config/generic.yaml b/src/main/resources/bidder-config/generic.yaml index 57ab0ca72e8..9b6aa4dffba 100644 --- a/src/main/resources/bidder-config/generic.yaml +++ b/src/main/resources/bidder-config/generic.yaml @@ -93,7 +93,7 @@ adapters: url: https://prebid.cwi.re/v1/usersync?gdpr={gdpr}&gdpr_consent={gdpr_consent}&rd={redirect_url} uid-macro: '$UID' iframe: - url: https://prebid.cwi.re/v1/usersync?gdpr={gdpr}&gdpr_consent={gdpr_consent}&rd={redirect_url} + url: https://prebid.cwi.re/v1/usersync?gdpr={gdpr}&gdpr_consent={gdpr_consent}&rd={redirect_url} uid-macro: '$UID' meta-info: maintainer-email: maintainer@example.com diff --git a/src/main/resources/bidder-config/huaweiads.yaml b/src/main/resources/bidder-config/huaweiads.yaml index cfa5fe8ffd3..683e4ab78e3 100644 --- a/src/main/resources/bidder-config/huaweiads.yaml +++ b/src/main/resources/bidder-config/huaweiads.yaml @@ -13,8 +13,7 @@ adapters: extra-info: # todo: to be removed or moved to test properties pkgNameConvert: - - - convertedPkgName: com.example.pkgname1 + - convertedPkgName: com.example.pkgname1 unconvertedPkgNames: - com.example.p1 - com.example.p2 @@ -27,8 +26,7 @@ adapters: exceptionPkgNames: - com.example.p7 - com.example.p8 - - - convertedPkgName: com.example.pkgname2 + - convertedPkgName: com.example.pkgname2 unconvertedPkgNames: - com.example.p9 - com.example.p10 diff --git a/src/main/resources/bidder-config/kobler.yaml b/src/main/resources/bidder-config/kobler.yaml index cd49ef2ea75..71b4b97d349 100644 --- a/src/main/resources/bidder-config/kobler.yaml +++ b/src/main/resources/bidder-config/kobler.yaml @@ -10,7 +10,7 @@ adapters: meta-info: maintainer-email: bidding-support@kobler.no site-media-types: - - banner + - banner app-media-types: - - banner + - banner vendor-id: 0 diff --git a/src/main/resources/bidder-config/loyal.yaml b/src/main/resources/bidder-config/loyal.yaml index 07e67800974..5f51839d7fe 100644 --- a/src/main/resources/bidder-config/loyal.yaml +++ b/src/main/resources/bidder-config/loyal.yaml @@ -13,5 +13,5 @@ adapters: - banner - video - native - supported-vendors: [] + supported-vendors: [ ] vendor-id: 0 diff --git a/src/main/resources/bidder-config/ogury.yaml b/src/main/resources/bidder-config/ogury.yaml index 99f970b841f..3ea05e3e3be 100644 --- a/src/main/resources/bidder-config/ogury.yaml +++ b/src/main/resources/bidder-config/ogury.yaml @@ -8,8 +8,10 @@ adapters: maintainer-email: deliveryservices@ogury.co site-media-types: - banner + - video app-media-types: - banner + - video vendor-id: 31 usersync: cookie-family-name: ogury diff --git a/src/main/resources/bidder-config/oms.yaml b/src/main/resources/bidder-config/oms.yaml index 70894c9787d..463fbbab2c6 100644 --- a/src/main/resources/bidder-config/oms.yaml +++ b/src/main/resources/bidder-config/oms.yaml @@ -1,6 +1,7 @@ adapters: oms: endpoint: http://rt.marphezis.com/pbs?publisherId={PublisherId} + modifying-vast-xml-allowed: true meta-info: maintainer-email: prebid@onlinemediasolutions.com app-media-types: @@ -10,4 +11,9 @@ adapters: - banner - video supported-vendors: - vendor-id: 0 + vendor-id: 883 + usersync: + cookie-family-name: oms + iframe: + url: https://rt.marphezis.com/sync/pub?pubid=pbs&gdpr={gdpr}&gdpr_consent={gdpr_consent}&us_privacy={us_privacy}&gpp={gpp}&gpp_sid={gpp_sid}&rurl={redirect_url} + uid-macro: $USERID diff --git a/src/main/resources/bidder-config/preciso.yaml b/src/main/resources/bidder-config/preciso.yaml index 1632792e391..cf776a45e0f 100644 --- a/src/main/resources/bidder-config/preciso.yaml +++ b/src/main/resources/bidder-config/preciso.yaml @@ -16,7 +16,7 @@ adapters: vendor-id: 874 usersync: cookie-family-name: preciso - redirect: + redirect: url: https://ck.2trk.info/rtb/user/usersync.aspx?id=preciso_srl&gdpr={gdpr}&gdpr_consent={gdpr_consent}&us_privacy={us_privacy}&t=2&redir={redirect_url} uid-macro: '${PRECISO_USER_ID}' iframe: diff --git a/src/main/resources/bidder-config/roulax.yaml b/src/main/resources/bidder-config/roulax.yaml index 7d331b76752..f78fb4cd927 100644 --- a/src/main/resources/bidder-config/roulax.yaml +++ b/src/main/resources/bidder-config/roulax.yaml @@ -4,12 +4,12 @@ adapters: meta-info: maintainer-email: bussiness@roulax.io app-media-types: - - banner - - video - - native + - banner + - video + - native site-media-types: - - banner - - video - - native + - banner + - video + - native supported-vendors: vendor-id: 0 diff --git a/src/main/resources/bidder-config/scalibur.yaml b/src/main/resources/bidder-config/scalibur.yaml new file mode 100644 index 00000000000..fadbea062f7 --- /dev/null +++ b/src/main/resources/bidder-config/scalibur.yaml @@ -0,0 +1,22 @@ +adapters: + scalibur: + endpoint: http://{Host}.scalibur.io/adserver/ortb?type=prebid-server + geoscope: + - global + ortb-version: "2.6" + endpoint-compression: gzip + meta-info: + maintainer-email: support@scalibur.io + app-media-types: + - banner + - video + site-media-types: + - banner + - video + supported-vendors: + vendor-id: 1471 + usersync: + cookie-family-name: scalibur + iframe: + url: https://srv.scalibur.io/adserver/sync?type=iframe&gdpr={gdpr}&gdpr_consent={gdpr_consent}&us_privacy={us_privacy}&gpp={gpp}&&gpp_sid={gpp_sid}&redirect={redirect_url} + uid-macro: '[PBS_UID]' diff --git a/src/main/resources/bidder-config/seedtag.yaml b/src/main/resources/bidder-config/seedtag.yaml index b90ff16745c..314d0dbe64e 100644 --- a/src/main/resources/bidder-config/seedtag.yaml +++ b/src/main/resources/bidder-config/seedtag.yaml @@ -4,6 +4,9 @@ adapters: endpoint-compression: gzip meta-info: maintainer-email: prebid@seedtag.com + app-media-types: + - banner + - video site-media-types: - banner - video diff --git a/src/main/resources/bidder-config/sevio.yaml b/src/main/resources/bidder-config/sevio.yaml new file mode 100644 index 00000000000..6bb520c4648 --- /dev/null +++ b/src/main/resources/bidder-config/sevio.yaml @@ -0,0 +1,13 @@ +adapters: + sevio: + endpoint: https://req.adx.ws/rtb + meta-info: + maintainer-email: technical@sevio.com + app-media-types: + - banner + - native + site-media-types: + - banner + - native + supported-vendors: + vendor-id: 1393 diff --git a/src/main/resources/bidder-config/smarthub.yaml b/src/main/resources/bidder-config/smarthub.yaml index 8ed2e05b854..9edde91f97f 100644 --- a/src/main/resources/bidder-config/smarthub.yaml +++ b/src/main/resources/bidder-config/smarthub.yaml @@ -1,45 +1,45 @@ adapters: smarthub: - endpoint: https://prebid.attekmi.com/pbserver?partnerName={Host}&seat={AccountID}&token={SourceId} + endpoint: https://prebid.attekmi.co/pbserver?partnerName={Host}&seat={AccountID}&token={SourceId} aliases: markapp: enabled: false - endpoint: https://markapp-prebid.attekmi.com/pbserver/?seat={AccountID}&token={SourceId} + endpoint: https://markapp-prebid.attekmi.co/pbserver/?seat={AccountID}&token={SourceId} meta-info: vendor-id: 0 jdpmedia: enabled: false - endpoint: https://jdpmedia-prebid.attekmi.com/pbserver/?seat={AccountID}&token={SourceId} + endpoint: https://jdpmedia-prebid.attekmi.co/pbserver/?seat={AccountID}&token={SourceId} meta-info: vendor-id: 0 tredio: enabled: false - endpoint: https://tredio-prebid.attekmi.com/pbserver/?seat={AccountID}&token={SourceId} + endpoint: https://tredio-prebid.attekmi.co/pbserver/?seat={AccountID}&token={SourceId} meta-info: vendor-id: 0 felixads: enabled: false - endpoint: https://felixads-prebid.attekmi.com/pbserver/?seat={AccountID}&token={SourceId} + endpoint: https://felixads-prebid.attekmi.co/pbserver/?seat={AccountID}&token={SourceId} meta-info: vendor-id: 0 jambojar: enabled: false - endpoint: https://jambojar-prebid.attekmi.com/pbserver/?seat={AccountID}&token={SourceId} + endpoint: https://jambojar-prebid.attekmi.co/pbserver/?seat={AccountID}&token={SourceId} meta-info: vendor-id: 0 adinify: enabled: false - endpoint: https://adinify-prebid.attekmi.com/pbserver/?seat={AccountID}&token={SourceId} + endpoint: https://adinify-prebid.attekmi.co/pbserver/?seat={AccountID}&token={SourceId} meta-info: vendor-id: 0 artechnology: enabled: false - endpoint: https://artechnology-prebid.attekmi.com/pbserver/?seat={AccountID}&token={SourceId} + endpoint: https://artechnology-prebid.attekmi.co/pbserver/?seat={AccountID}&token={SourceId} meta-info: vendor-id: 0 addigi: enabled: false - endpoint: https://addigi-prebid.attekmi.com/pbserver/?seat={AccountID}&token={SourceId} + endpoint: https://addigi-prebid.attekmi.co/pbserver/?seat={AccountID}&token={SourceId} meta-info: vendor-id: 0 radiantfusion: diff --git a/src/main/resources/bidder-config/sparteo.yaml b/src/main/resources/bidder-config/sparteo.yaml index 5ae06817ba8..22100648fb3 100644 --- a/src/main/resources/bidder-config/sparteo.yaml +++ b/src/main/resources/bidder-config/sparteo.yaml @@ -1,7 +1,7 @@ adapters: sparteo: endpoint: https://bid.sparteo.com/s2s-auction - meta-info: + meta-info: maintainer-email: prebid@sparteo.com app-media-types: - banner diff --git a/src/main/resources/bidder-config/synapsehx.yaml b/src/main/resources/bidder-config/synapsehx.yaml new file mode 100644 index 00000000000..ede5ccf6469 --- /dev/null +++ b/src/main/resources/bidder-config/synapsehx.yaml @@ -0,0 +1,21 @@ +adapters: + synapsehx: + endpoint: https://rtb.hx.compasonline.com/pbs + openrtb-version: 2.6 + meta-info: + maintainer-email: prebid@compas-inc.com + app-media-types: + - banner + - video + site-media-types: + - banner + - video + vendor-id: 0 + usersync: + cookie-family-name: synapsehx + redirect: + url: https://sync.hx.compasonline.com/pbserver/image?gdpr={gdpr}&gdpr_consent={gdpr_consent}&ccpa={us_privacy}&gpp={gpp}&gpp_sid={gpp_sid}&redirect={redirect_url} + uid-macro: "${VISITOR_ID}" + iframe: + url: https://sync.hx.compasonline.com/pbserver/iframe?gdpr={gdpr}&gdpr_consent={gdpr_consent}&ccpa={us_privacy}&gpp={gpp}&gpp_sid={gpp_sid}&redirect={redirect_url} + uid-macro: "${VISITOR_ID}" diff --git a/src/main/resources/bidder-config/teqblaze.yaml b/src/main/resources/bidder-config/teqblaze.yaml index d6c34012379..4c2c4af5a3c 100644 --- a/src/main/resources/bidder-config/teqblaze.yaml +++ b/src/main/resources/bidder-config/teqblaze.yaml @@ -115,6 +115,12 @@ adapters: meta-info: maintainer-email: prebid@adsmovil.com vendor-id: 0 + appMonstaMedia: + enabled: false + endpoint: https://ssp-us.appmonsta.ai/pserver + meta-info: + maintainer-email: media.support@appmonsta.ai + vendor-id: 1283 meta-info: maintainer-email: github@teqblaze.com app-media-types: diff --git a/src/main/resources/bidder-config/thetradedesk.yaml b/src/main/resources/bidder-config/thetradedesk.yaml index 628e3b149fa..421cf00a91f 100644 --- a/src/main/resources/bidder-config/thetradedesk.yaml +++ b/src/main/resources/bidder-config/thetradedesk.yaml @@ -1,6 +1,7 @@ adapters: thetradedesk: endpoint: https://direct.adsrvr.org/bid/bidder/{SupplyId} + ortb-version: "2.6" aliases: ttd: meta-info: @@ -10,10 +11,12 @@ adapters: app-media-types: - banner - video + - audio - native site-media-types: - banner - video + - audio - native supported-vendors: vendor-id: 21 diff --git a/src/main/resources/bidder-config/ucfunnel.yaml b/src/main/resources/bidder-config/ucfunnel.yaml index 3dd90565544..db67ff1868d 100644 --- a/src/main/resources/bidder-config/ucfunnel.yaml +++ b/src/main/resources/bidder-config/ucfunnel.yaml @@ -14,6 +14,6 @@ adapters: usersync: cookie-family-name: ucfunnel redirect: - # for syncing to work, please register your Prebid Server domain with the contact email above + # for syncing to work, please register your Prebid Server domain with the contact email above url: https://sync.aralego.com/idsync?gdpr={gdpr}&gdpr_consent={gdpr_consent}&usprivacy={us_privacy}&redirect={redirect_url} uid-macro: 'SspCookieUserId' diff --git a/src/main/resources/static/bidder-params/aceex.json b/src/main/resources/static/bidder-params/aceex.json index 9fb97d41136..86af1e292c1 100644 --- a/src/main/resources/static/bidder-params/aceex.json +++ b/src/main/resources/static/bidder-params/aceex.json @@ -10,5 +10,7 @@ "minLength": 1 } }, - "required": ["accountid"] + "required": [ + "accountid" + ] } diff --git a/src/main/resources/static/bidder-params/acuityads.json b/src/main/resources/static/bidder-params/acuityads.json index 314a6cb5f8d..c0c59325b04 100644 --- a/src/main/resources/static/bidder-params/acuityads.json +++ b/src/main/resources/static/bidder-params/acuityads.json @@ -15,5 +15,8 @@ "minLength": 1 } }, - "required": ["host", "accountid"] + "required": [ + "host", + "accountid" + ] } diff --git a/src/main/resources/static/bidder-params/adelement.json b/src/main/resources/static/bidder-params/adelement.json index 95e3a8f7a3c..2631fd60e41 100644 --- a/src/main/resources/static/bidder-params/adelement.json +++ b/src/main/resources/static/bidder-params/adelement.json @@ -10,5 +10,7 @@ "minLength": 1 } }, - "required": ["supply_id"] + "required": [ + "supply_id" + ] } diff --git a/src/main/resources/static/bidder-params/adgeneration.json b/src/main/resources/static/bidder-params/adgeneration.json index 7125fc8e89e..3f156688a24 100644 --- a/src/main/resources/static/bidder-params/adgeneration.json +++ b/src/main/resources/static/bidder-params/adgeneration.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "AdGeneration Adapter Params", "description": "A schema which validates params accepted by the AdGeneration adapter", - "type": "object", "properties": { "id": { @@ -10,5 +9,7 @@ "description": "Ad ID registered by AdGeneration." } }, - "required": ["id"] -} \ No newline at end of file + "required": [ + "id" + ] +} diff --git a/src/main/resources/static/bidder-params/adhese.json b/src/main/resources/static/bidder-params/adhese.json index 6dfdb1dbc8f..a5cba073a6b 100644 --- a/src/main/resources/static/bidder-params/adhese.json +++ b/src/main/resources/static/bidder-params/adhese.json @@ -21,5 +21,9 @@ "description": "Target params, as defined in your Adhese setup." } }, - "required": ["account", "location", "format"] + "required": [ + "account", + "location", + "format" + ] } diff --git a/src/main/resources/static/bidder-params/adman.json b/src/main/resources/static/bidder-params/adman.json index 2db8d4a2817..7f353b23484 100644 --- a/src/main/resources/static/bidder-params/adman.json +++ b/src/main/resources/static/bidder-params/adman.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Adman Adapter Params", "description": "A schema which validates params accepted by the Adman adapter", - "type": "object", "properties": { "TagID": { @@ -10,5 +9,7 @@ "description": "An ID which identifies the adman ad tag" } }, - "required" : [ "TagID" ] + "required": [ + "TagID" + ] } diff --git a/src/main/resources/static/bidder-params/admixer.json b/src/main/resources/static/bidder-params/admixer.json index 78671931561..96231c30015 100644 --- a/src/main/resources/static/bidder-params/admixer.json +++ b/src/main/resources/static/bidder-params/admixer.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Admixer Adapter Params", "description": "A schema which validates params accepted by the Admixer adapter", - "type": "object", "properties": { "zone": { @@ -20,6 +19,7 @@ "description": "User-defined targeting key-value pairs." } }, - - "required": ["zone"] -} \ No newline at end of file + "required": [ + "zone" + ] +} diff --git a/src/main/resources/static/bidder-params/adnuntius.json b/src/main/resources/static/bidder-params/adnuntius.json index ded668b5bbc..f114c6573d5 100644 --- a/src/main/resources/static/bidder-params/adnuntius.json +++ b/src/main/resources/static/bidder-params/adnuntius.json @@ -25,7 +25,6 @@ "description": "Allows you to specify Net or Gross bids." } }, - "required": [ "auId" ] diff --git a/src/main/resources/static/bidder-params/adot.json b/src/main/resources/static/bidder-params/adot.json index 45caca4da80..3258feceb02 100644 --- a/src/main/resources/static/bidder-params/adot.json +++ b/src/main/resources/static/bidder-params/adot.json @@ -14,7 +14,10 @@ }, "publisherPath": { "type": "string", - "enum": ["/hubvisor", "/spotx"], + "enum": [ + "/hubvisor", + "/spotx" + ], "description": "An optional path used in the bid endpoint. Only '/hubvisor' and '/spotx' are allowed." } }, diff --git a/src/main/resources/static/bidder-params/adswag.json b/src/main/resources/static/bidder-params/adswag.json new file mode 100644 index 00000000000..f34276c4da1 --- /dev/null +++ b/src/main/resources/static/bidder-params/adswag.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Adswag Adapter Params", + "description": "A schema which validates params accepted by the Adswag adapter", + "type": "object", + "properties": { + "publisherId": { + "type": "string", + "minLength": 1, + "description": "Adswag publisher id (issued at onboarding)" + }, + "placementId": { + "type": "string", + "minLength": 1, + "description": "Explicit placement override; omit to let Adswag discover the placement from GPID or the ad unit code" + } + }, + "required": [ + "publisherId" + ] +} diff --git a/src/main/resources/static/bidder-params/adtarget.json b/src/main/resources/static/bidder-params/adtarget.json index 195bf2dd430..bf86d98047b 100644 --- a/src/main/resources/static/bidder-params/adtarget.json +++ b/src/main/resources/static/bidder-params/adtarget.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Adtarget Adapter Params", "description": "A schema which validates params accepted by the Adtarget adapter", - "type": "object", "properties": { "placementId": { @@ -22,5 +21,7 @@ "description": "BidFloor, US Dollars" } }, - "required": ["aid"] + "required": [ + "aid" + ] } diff --git a/src/main/resources/static/bidder-params/adtelligent.json b/src/main/resources/static/bidder-params/adtelligent.json index e8dedf33690..258f6e35117 100644 --- a/src/main/resources/static/bidder-params/adtelligent.json +++ b/src/main/resources/static/bidder-params/adtelligent.json @@ -24,5 +24,7 @@ "description": "BidFloor, US Dollars" } }, - "required": ["aid"] + "required": [ + "aid" + ] } diff --git a/src/main/resources/static/bidder-params/adtrgtme.json b/src/main/resources/static/bidder-params/adtrgtme.json index 3d6a2a1e1c9..c68d716b0db 100644 --- a/src/main/resources/static/bidder-params/adtrgtme.json +++ b/src/main/resources/static/bidder-params/adtrgtme.json @@ -3,13 +3,13 @@ "title": "Adtrgtme adapter params", "description": "A schema which validates params accepted by the Adtrgtme adapter", "type": "object", - "properties": { "site_id": { "type": "integer", "description": "Site ID" } }, - - "required": ["site_id"] + "required": [ + "site_id" + ] } diff --git a/src/main/resources/static/bidder-params/adverxo.json b/src/main/resources/static/bidder-params/adverxo.json index 072abe4df99..c1ace8afa0b 100644 --- a/src/main/resources/static/bidder-params/adverxo.json +++ b/src/main/resources/static/bidder-params/adverxo.json @@ -15,5 +15,8 @@ "description": "Authentication token provided by Adverxo platform for the AdUnit." } }, - "required": ["adUnitId", "auth"] + "required": [ + "adUnitId", + "auth" + ] } diff --git a/src/main/resources/static/bidder-params/adview.json b/src/main/resources/static/bidder-params/adview.json index 015bae5d700..b16c10c70e1 100644 --- a/src/main/resources/static/bidder-params/adview.json +++ b/src/main/resources/static/bidder-params/adview.json @@ -15,5 +15,8 @@ "minLength": 1 } }, - "required": ["placementId", "accountId"] + "required": [ + "placementId", + "accountId" + ] } diff --git a/src/main/resources/static/bidder-params/adyoulike.json b/src/main/resources/static/bidder-params/adyoulike.json index 448de344739..fa0f59b37bc 100644 --- a/src/main/resources/static/bidder-params/adyoulike.json +++ b/src/main/resources/static/bidder-params/adyoulike.json @@ -29,5 +29,7 @@ "description": "Arbitrary id used for debug purpose" } }, - "required": ["placement"] + "required": [ + "placement" + ] } diff --git a/src/main/resources/static/bidder-params/aja.json b/src/main/resources/static/bidder-params/aja.json index 4d18a59bc2b..91311437a95 100644 --- a/src/main/resources/static/bidder-params/aja.json +++ b/src/main/resources/static/bidder-params/aja.json @@ -9,5 +9,7 @@ "description": "Ad spot ID" } }, - "required": ["asi"] -} \ No newline at end of file + "required": [ + "asi" + ] +} diff --git a/src/main/resources/static/bidder-params/algorix.json b/src/main/resources/static/bidder-params/algorix.json index 5b2cadf5ed1..9ce7e3d11bd 100644 --- a/src/main/resources/static/bidder-params/algorix.json +++ b/src/main/resources/static/bidder-params/algorix.json @@ -24,9 +24,16 @@ }, "region": { "type": "string", - "enum": ["APAC", "USE", "EUC"], + "enum": [ + "APAC", + "USE", + "EUC" + ], "description": "Server region for PBS request, null for global, APAC for SG Region, US for USE Region, EUC for EU Region." } }, - "required": ["sid", "token"] + "required": [ + "sid", + "token" + ] } diff --git a/src/main/resources/static/bidder-params/alkimi.json b/src/main/resources/static/bidder-params/alkimi.json index 93e09022469..6331a7a375c 100644 --- a/src/main/resources/static/bidder-params/alkimi.json +++ b/src/main/resources/static/bidder-params/alkimi.json @@ -3,7 +3,6 @@ "title": "Alkimi Adapter Params", "description": "A schema which validates params accepted by the Alkimi adapter", "type": "object", - "properties": { "token": { "type": "string", @@ -23,6 +22,7 @@ "description": "Advisory as to the number of seconds that may elapse between the auction and the actual impression" } }, - - "required": ["token"] + "required": [ + "token" + ] } diff --git a/src/main/resources/static/bidder-params/alliance_gravity.json b/src/main/resources/static/bidder-params/alliance_gravity.json index b2c122f710b..da3128d5741 100644 --- a/src/main/resources/static/bidder-params/alliance_gravity.json +++ b/src/main/resources/static/bidder-params/alliance_gravity.json @@ -10,5 +10,7 @@ "minLength": 1 } }, - "required": ["srid"] + "required": [ + "srid" + ] } diff --git a/src/main/resources/static/bidder-params/amx.json b/src/main/resources/static/bidder-params/amx.json index f9b1b26b3db..d63479376c6 100644 --- a/src/main/resources/static/bidder-params/amx.json +++ b/src/main/resources/static/bidder-params/amx.json @@ -4,7 +4,7 @@ "description": "A schema to validate params accepted by the AMX adapter", "type": "object", "properties": { - "tagId" : { + "tagId": { "type": "string", "description": "Set a tagId (overrides site.publisher.id, or app.publisher.id)" }, diff --git a/src/main/resources/static/bidder-params/appnexus.json b/src/main/resources/static/bidder-params/appnexus.json index 8d3675765f3..7ed21161c9c 100644 --- a/src/main/resources/static/bidder-params/appnexus.json +++ b/src/main/resources/static/bidder-params/appnexus.json @@ -27,7 +27,10 @@ "description": "Deprecated, use inv_code instead." }, "member": { - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "description": "An ID which identifies the member selling the impression." }, "keywords": { diff --git a/src/main/resources/static/bidder-params/appush.json b/src/main/resources/static/bidder-params/appush.json index 72dca18b55d..da2f992a1b0 100644 --- a/src/main/resources/static/bidder-params/appush.json +++ b/src/main/resources/static/bidder-params/appush.json @@ -3,7 +3,6 @@ "title": "Appush Adapter Params", "description": "A schema which validates params accepted by the Appush adapter", "type": "object", - "properties": { "placementId": { "type": "string", @@ -17,7 +16,15 @@ } }, "oneOf": [ - { "required": ["placementId"] }, - { "required": ["endpointId"] } + { + "required": [ + "placementId" + ] + }, + { + "required": [ + "endpointId" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/aso.json b/src/main/resources/static/bidder-params/aso.json index edb3c0feb9c..3db7125220e 100644 --- a/src/main/resources/static/bidder-params/aso.json +++ b/src/main/resources/static/bidder-params/aso.json @@ -9,5 +9,7 @@ "description": "An ID which identifies the zone selling the impression" } }, - "required": ["zone"] + "required": [ + "zone" + ] } diff --git a/src/main/resources/static/bidder-params/automatad.json b/src/main/resources/static/bidder-params/automatad.json index ae0ce7d2f15..357278f1aa5 100644 --- a/src/main/resources/static/bidder-params/automatad.json +++ b/src/main/resources/static/bidder-params/automatad.json @@ -3,7 +3,6 @@ "title": "Automatad Adapter Params", "description": "A schema which validates params accepted by the Automatad adapter", "type": "object", - "properties": { "position": { "type": "string", diff --git a/src/main/resources/static/bidder-params/avocet.json b/src/main/resources/static/bidder-params/avocet.json index f27e5950f7c..0ce91c7a793 100644 --- a/src/main/resources/static/bidder-params/avocet.json +++ b/src/main/resources/static/bidder-params/avocet.json @@ -15,10 +15,14 @@ }, "oneOf": [ { - "required": ["placement"] + "required": [ + "placement" + ] }, { - "required": ["placement_code"] + "required": [ + "placement_code" + ] } ] } diff --git a/src/main/resources/static/bidder-params/axonix.json b/src/main/resources/static/bidder-params/axonix.json index 7a3762ce5e2..f41229460a8 100644 --- a/src/main/resources/static/bidder-params/axonix.json +++ b/src/main/resources/static/bidder-params/axonix.json @@ -10,5 +10,7 @@ "description": "Unique supply identifier" } }, - "required": ["supplyId"] + "required": [ + "supplyId" + ] } diff --git a/src/main/resources/static/bidder-params/beachfront.json b/src/main/resources/static/bidder-params/beachfront.json index 624045291ac..9edb64f4dfb 100644 --- a/src/main/resources/static/bidder-params/beachfront.json +++ b/src/main/resources/static/bidder-params/beachfront.json @@ -23,21 +23,38 @@ "description": "An appId string that will be applied to banner requests in this imp." } }, - "anyOf":[ - {"required":["video"]}, - {"required":["banner"]} + "anyOf": [ + { + "required": [ + "video" + ] + }, + { + "required": [ + "banner" + ] + } ] }, "bidfloor": { "type": "number", - "description": "The price floor for the bid. Will override the bidfloor set for the impression." }, + "description": "The price floor for the bid. Will override the bidfloor set for the impression." + }, "videoResponseType": { "type": "string", "description": "By default the video response will be an AdM element containing VAST 3.0 markup including tracking, click through, and mediafile elements pointing to mp4, webm or other playable media files or Vpaid media as configured for the exchange at beachfront.io. Optionally, set this to 'nurl' to receive a URI pointing to VAST 3.0 markup which will contain a mediafile pointing to a beachfront neptune javascript video player which will load your video and take care of tracking, etc. Regardless of which format is selected, the id of the returned impression will be the provided impression id (imp[{'id'...},...] in the request) with the format appended. The impression id will be returned unchanged as 'impid'. So if you indicate 'nurl', and an impression id 'someImp', the returned impression will have an 'impid' value of 'someImp', and the 'id' value 'someImpNurlVideo'. This is to differentiate the object in the case that a request includes both video and banner elements. Setting videoResponseType to any other string will have no effect and the default format (AdM) will be returned." } }, "oneOf": [ - {"required": ["appId"] }, - {"required": ["appIds"]} + { + "required": [ + "appId" + ] + }, + { + "required": [ + "appIds" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/beintoo.json b/src/main/resources/static/bidder-params/beintoo.json index ba0ed4b8ec5..5cd1aa2c5bc 100644 --- a/src/main/resources/static/bidder-params/beintoo.json +++ b/src/main/resources/static/bidder-params/beintoo.json @@ -4,7 +4,7 @@ "description": "A schema which validates params accepted by the Beintoo adapter", "type": "object", "properties": { - "tagid" : { + "tagid": { "type": "string", "description": "The id of an inventory target" }, @@ -13,6 +13,7 @@ "description": "The minimum price acceptable for a bid" } }, - - "required": ["tagid"] + "required": [ + "tagid" + ] } diff --git a/src/main/resources/static/bidder-params/between.json b/src/main/resources/static/bidder-params/between.json index 1fdab678122..604a6eaa87e 100644 --- a/src/main/resources/static/bidder-params/between.json +++ b/src/main/resources/static/bidder-params/between.json @@ -7,7 +7,12 @@ "host": { "type": "string", "description": "Optional network host to request from, used when host macro provided in config", - "enum": ["lbs-eu1.ads", "lbs-ru1.ads", "lbs-us-east1.ads", "lbs-asia1.ads"] + "enum": [ + "lbs-eu1.ads", + "lbs-ru1.ads", + "lbs-us-east1.ads", + "lbs-asia1.ads" + ] }, "publisher_id": { "type": "string", diff --git a/src/main/resources/static/bidder-params/beyondmedia.json b/src/main/resources/static/bidder-params/beyondmedia.json index 31e4017b5c1..3e1592e18c1 100644 --- a/src/main/resources/static/bidder-params/beyondmedia.json +++ b/src/main/resources/static/bidder-params/beyondmedia.json @@ -3,7 +3,6 @@ "title": "AndBeyond.Media Adapter Params", "description": "A schema which validates params accepted by the AndBeyond.Media adapter", "type": "object", - "properties": { "placementId": { "type": "string", @@ -11,5 +10,7 @@ "description": "Placement ID" } }, - "required": ["placementId"] + "required": [ + "placementId" + ] } diff --git a/src/main/resources/static/bidder-params/bidmyadz.json b/src/main/resources/static/bidder-params/bidmyadz.json index b45b48a7c30..0f831387fa4 100644 --- a/src/main/resources/static/bidder-params/bidmyadz.json +++ b/src/main/resources/static/bidder-params/bidmyadz.json @@ -8,5 +8,7 @@ "type": "string" } }, - "required": ["placementId"] -} \ No newline at end of file + "required": [ + "placementId" + ] +} diff --git a/src/main/resources/static/bidder-params/bidscube.json b/src/main/resources/static/bidder-params/bidscube.json index 88dc91ab391..ecca04ff0b8 100644 --- a/src/main/resources/static/bidder-params/bidscube.json +++ b/src/main/resources/static/bidder-params/bidscube.json @@ -14,5 +14,7 @@ "description": "User-defined targeting key-value pairs." } }, - "required" : [ "placementId" ] + "required": [ + "placementId" + ] } diff --git a/src/main/resources/static/bidder-params/bidwave.json b/src/main/resources/static/bidder-params/bidwave.json new file mode 100644 index 00000000000..d7edfaed1ad --- /dev/null +++ b/src/main/resources/static/bidder-params/bidwave.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "BidWave Adapter Params", + "description": "A schema which validates params accepted by the BidWave adapter", + "type": "object", + "properties": { + "publisherId": { + "type": "string", + "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$", + "description": "Publisher ID" + } + }, + "required": [ + "publisherId" + ] +} diff --git a/src/main/resources/static/bidder-params/boldwin.json b/src/main/resources/static/bidder-params/boldwin.json index 6c3d0a99228..542e95820e5 100644 --- a/src/main/resources/static/bidder-params/boldwin.json +++ b/src/main/resources/static/bidder-params/boldwin.json @@ -3,7 +3,6 @@ "title": "Boldwin Adapter Params", "description": "A schema which validates params accepted by the Boldwin adapter", "type": "object", - "properties": { "placementId": { "type": "string", @@ -17,7 +16,15 @@ } }, "oneOf": [ - { "required": ["placementId"] }, - { "required": ["endpointId"] } + { + "required": [ + "placementId" + ] + }, + { + "required": [ + "endpointId" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/ccx.json b/src/main/resources/static/bidder-params/ccx.json index 643a17f61cb..b340f83a043 100644 --- a/src/main/resources/static/bidder-params/ccx.json +++ b/src/main/resources/static/bidder-params/ccx.json @@ -9,5 +9,7 @@ "description": "Placement ID" } }, - "required": ["placementId"] + "required": [ + "placementId" + ] } diff --git a/src/main/resources/static/bidder-params/clydo.json b/src/main/resources/static/bidder-params/clydo.json index 71b60d09405..bca3a83bd8e 100644 --- a/src/main/resources/static/bidder-params/clydo.json +++ b/src/main/resources/static/bidder-params/clydo.json @@ -12,9 +12,15 @@ "region": { "type": "string", "description": "Regional endpoint identifier (us, usw, eu, apac)", - "enum": ["us", "usw", "eu", "apac"] + "enum": [ + "us", + "usw", + "eu", + "apac" + ] } }, - - "required": ["partnerId"] + "required": [ + "partnerId" + ] } diff --git a/src/main/resources/static/bidder-params/compass.json b/src/main/resources/static/bidder-params/compass.json index 18a2f90d610..12ea420964a 100644 --- a/src/main/resources/static/bidder-params/compass.json +++ b/src/main/resources/static/bidder-params/compass.json @@ -3,7 +3,6 @@ "title": "Compass Adapter Params", "description": "A schema which validates params accepted by the Compass adapter", "type": "object", - "properties": { "placementId": { "type": "string", @@ -17,7 +16,15 @@ } }, "oneOf": [ - { "required": ["placementId"] }, - { "required": ["endpointId"] } + { + "required": [ + "placementId" + ] + }, + { + "required": [ + "endpointId" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/connatix.json b/src/main/resources/static/bidder-params/connatix.json index 697e9cd1529..7b5855c058f 100644 --- a/src/main/resources/static/bidder-params/connatix.json +++ b/src/main/resources/static/bidder-params/connatix.json @@ -16,6 +16,8 @@ "maximum": 1 } }, - "required": ["placementId"] + "required": [ + "placementId" + ] } diff --git a/src/main/resources/static/bidder-params/connectad.json b/src/main/resources/static/bidder-params/connectad.json index e36410928da..5a6f6ec9294 100644 --- a/src/main/resources/static/bidder-params/connectad.json +++ b/src/main/resources/static/bidder-params/connectad.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "ConnectAd S2S dapter Params", + "title": "ConnectAd S2S Adapter Params", "description": "A schema which validates params accepted by the ConnectAd Adapter", "type": "object", "properties": { @@ -20,7 +20,11 @@ }, "bidfloor": { "type": "number", - "description": "Requests Floorprice" + "description": "Requested Floorprice" + }, + "endpointUrl": { + "type": "string", + "description": "Client-side only (Prebid.js): override the bid endpoint URL for testing or a custom datacenter. Ignored by Prebid Server, which always uses its configured endpoint." } }, "required": [ diff --git a/src/main/resources/static/bidder-params/consumable.json b/src/main/resources/static/bidder-params/consumable.json index 14cb4fb5d24..f09425ad6b4 100644 --- a/src/main/resources/static/bidder-params/consumable.json +++ b/src/main/resources/static/bidder-params/consumable.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Consumable Adapter Params", "description": "A schema which validates params accepted by the Consumable adapter", - "type": "object", "properties": { "siteId": { @@ -26,5 +25,9 @@ "pattern": "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$" } }, - "required": ["siteId", "networkId","unitId"] -} \ No newline at end of file + "required": [ + "siteId", + "networkId", + "unitId" + ] +} diff --git a/src/main/resources/static/bidder-params/cpmstar.json b/src/main/resources/static/bidder-params/cpmstar.json index 2b37c54a0fb..c021e7df357 100644 --- a/src/main/resources/static/bidder-params/cpmstar.json +++ b/src/main/resources/static/bidder-params/cpmstar.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Cpmstar Adapter Params", "description": "Schema to validate params accepted by the Cpmstar adapter", - "type": "object", "properties": { "placementId": { @@ -14,5 +13,7 @@ "description": "Cpmstar-specific ID for ad subpool" } }, - "required": ["placementId"] + "required": [ + "placementId" + ] } diff --git a/src/main/resources/static/bidder-params/decenterads.json b/src/main/resources/static/bidder-params/decenterads.json index 970e99038a0..0ff008889b5 100644 --- a/src/main/resources/static/bidder-params/decenterads.json +++ b/src/main/resources/static/bidder-params/decenterads.json @@ -14,5 +14,7 @@ "description": "User-defined targeting key-value pairs." } }, - "required" : [ "placementId" ] + "required": [ + "placementId" + ] } diff --git a/src/main/resources/static/bidder-params/deepintent.json b/src/main/resources/static/bidder-params/deepintent.json index 772938805f1..51b15231474 100644 --- a/src/main/resources/static/bidder-params/deepintent.json +++ b/src/main/resources/static/bidder-params/deepintent.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Deepintent Adapter Params", "description": "A schema which validates params accepted by the Deepintent adapter", - "type": "object", "properties": { "tagId": { @@ -10,5 +9,7 @@ "description": "An ID which identifies the deepintent ad tag" } }, - "required" : [ "tagId" ] + "required": [ + "tagId" + ] } diff --git a/src/main/resources/static/bidder-params/dianomi.json b/src/main/resources/static/bidder-params/dianomi.json index 5eaef10d886..deeeaa7a81b 100644 --- a/src/main/resources/static/bidder-params/dianomi.json +++ b/src/main/resources/static/bidder-params/dianomi.json @@ -5,16 +5,22 @@ "type": "object", "properties": { "smartadId": { - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "pattern": "^\\d+$", "description": "An ID which identifies the smartad/placement selling the impression" }, "priceType": { - "type": ["string"], + "type": [ + "string" + ], "description": "gross or net. Default is net.", "pattern": "gross|net" } }, - - "required": ["smartadId"] + "required": [ + "smartadId" + ] } diff --git a/src/main/resources/static/bidder-params/dmx.json b/src/main/resources/static/bidder-params/dmx.json index fa2d447b5d2..731079539e2 100644 --- a/src/main/resources/static/bidder-params/dmx.json +++ b/src/main/resources/static/bidder-params/dmx.json @@ -4,15 +4,15 @@ "description": "A schema which validates params accepted by the DMX adapter", "type": "object", "properties": { - "memberid" : { + "memberid": { "type": "string", "description": "Represent boost MemberId from districtm UI" }, - "placement_id" : { + "placement_id": { "type": "string", "description": "memberid replacement / alternative value or equivalent" }, - "seller_id" : { + "seller_id": { "type": "string", "description": "Represent DMX Partner when you get onboarded, this is for specific setup BURL vs NURL" }, @@ -29,6 +29,7 @@ "description": "The minimum price acceptable for a bid, this is optional since we do get the one from the original openrtb request" } }, - - "required": ["memberid"] + "required": [ + "memberid" + ] } diff --git a/src/main/resources/static/bidder-params/e_volution.json b/src/main/resources/static/bidder-params/e_volution.json index c4a55373212..b98dc732a8e 100644 --- a/src/main/resources/static/bidder-params/e_volution.json +++ b/src/main/resources/static/bidder-params/e_volution.json @@ -9,5 +9,7 @@ "description": "network or placement key" } }, - "required": ["key"] -} \ No newline at end of file + "required": [ + "key" + ] +} diff --git a/src/main/resources/static/bidder-params/edge226.json b/src/main/resources/static/bidder-params/edge226.json index 67c8fe76c88..b93d8ab4c8a 100644 --- a/src/main/resources/static/bidder-params/edge226.json +++ b/src/main/resources/static/bidder-params/edge226.json @@ -3,7 +3,6 @@ "title": "Edge226 Adapter Params", "description": "A schema which validates params accepted by the Edge226 adapter", "type": "object", - "properties": { "placementId": { "type": "string", @@ -17,7 +16,15 @@ } }, "oneOf": [ - { "required": ["placementId"] }, - { "required": ["endpointId"] } + { + "required": [ + "placementId" + ] + }, + { + "required": [ + "endpointId" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/elementaltv.json b/src/main/resources/static/bidder-params/elementaltv.json index f80e6c4f0d7..31294cad8aa 100644 --- a/src/main/resources/static/bidder-params/elementaltv.json +++ b/src/main/resources/static/bidder-params/elementaltv.json @@ -9,5 +9,7 @@ "description": "AdUnit to bid against to." } }, - "required": ["adunit"] + "required": [ + "adunit" + ] } diff --git a/src/main/resources/static/bidder-params/emxdigital.json b/src/main/resources/static/bidder-params/emxdigital.json index 16b2b70186f..0f7223e038b 100644 --- a/src/main/resources/static/bidder-params/emxdigital.json +++ b/src/main/resources/static/bidder-params/emxdigital.json @@ -4,7 +4,7 @@ "description": "A schema which validates params accepted by the EMX Digital adapter", "type": "object", "properties": { - "tagid" : { + "tagid": { "type": "string", "description": "The id of an inventory target" }, @@ -13,5 +13,7 @@ "description": "The minimum price acceptable for a bid" } }, - "required": ["tagid"] + "required": [ + "tagid" + ] } diff --git a/src/main/resources/static/bidder-params/epom.json b/src/main/resources/static/bidder-params/epom.json index ee8c14e4f7e..caf63c414b7 100644 --- a/src/main/resources/static/bidder-params/epom.json +++ b/src/main/resources/static/bidder-params/epom.json @@ -3,6 +3,5 @@ "title": "Epom Adapter Params", "description": "A schema which validates params accepted by the Epom adapter", "type": "object", - "properties": {} } diff --git a/src/main/resources/static/bidder-params/eskimi.json b/src/main/resources/static/bidder-params/eskimi.json new file mode 100644 index 00000000000..eabbdbdfc90 --- /dev/null +++ b/src/main/resources/static/bidder-params/eskimi.json @@ -0,0 +1,56 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Eskimi Adapter Params", + "description": "A schema which validates params accepted by the Eskimi adapter", + "type": "object", + "additionalProperties": false, + "properties": { + "placementId": { + "type": "integer", + "minimum": 1, + "description": "The Eskimi placement ID" + }, + "bidFloor": { + "type": "number", + "minimum": 0, + "description": "The minimum bid floor (USD unless bidFloorCur is set)" + }, + "bidFloorCur": { + "type": "string", + "description": "The currency of the bid floor" + }, + "bcat": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Blocked IAB advertiser categories" + }, + "badv": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Blocked advertiser domains" + }, + "bapp": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Blocked app bundles" + }, + "battr": { + "type": "array", + "items": { + "type": "integer", + "minimum": 1, + "maximum": 17 + }, + "description": "Blocked creative attributes (OpenRTB List 5.3)" + } + }, + "required": [ + "placementId" + ] +} diff --git a/src/main/resources/static/bidder-params/floxis.json b/src/main/resources/static/bidder-params/floxis.json new file mode 100644 index 00000000000..25ae803ea9d --- /dev/null +++ b/src/main/resources/static/bidder-params/floxis.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Floxis Adapter Params", + "description": "A schema which validates params accepted by the Floxis adapter", + "type": "object", + "properties": { + "seat": { + "type": "string", + "minLength": 1, + "description": "The Floxis seat ID this publisher buys through" + }, + "region": { + "type": "string", + "pattern": "^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$", + "description": "The Floxis region (DNS label, interpolated into the bidding host); defaults to us-e when omitted" + }, + "partner": { + "type": "string", + "pattern": "^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$", + "description": "The white-label partner (DNS label, interpolated into the bidding host); defaults to floxis when omitted" + } + }, + "required": [ + "seat" + ] +} diff --git a/src/main/resources/static/bidder-params/freewheelssp.json b/src/main/resources/static/bidder-params/freewheelssp.json index 166423674cb..57aa12aa4ad 100644 --- a/src/main/resources/static/bidder-params/freewheelssp.json +++ b/src/main/resources/static/bidder-params/freewheelssp.json @@ -5,7 +5,10 @@ "type": "object", "properties": { "zoneId": { - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "description": "Zone ID" } }, diff --git a/src/main/resources/static/bidder-params/frvradn.json b/src/main/resources/static/bidder-params/frvradn.json index 09edaba10cc..8a51aa96e1b 100644 --- a/src/main/resources/static/bidder-params/frvradn.json +++ b/src/main/resources/static/bidder-params/frvradn.json @@ -5,13 +5,20 @@ "type": "object", "properties": { "publisher_id": { - "type": ["string"], + "type": [ + "string" + ], "description": "Publisher ID" }, "ad_unit_id": { - "type": ["string"], + "type": [ + "string" + ], "description": "Ad Unit ID" } }, - "required": ["publisher_id", "ad_unit_id"] + "required": [ + "publisher_id", + "ad_unit_id" + ] } diff --git a/src/main/resources/static/bidder-params/inmobi.json b/src/main/resources/static/bidder-params/inmobi.json index 631b3137b72..0912ed9d8dd 100644 --- a/src/main/resources/static/bidder-params/inmobi.json +++ b/src/main/resources/static/bidder-params/inmobi.json @@ -5,9 +5,13 @@ "type": "object", "properties": { "plc": { - "type": ["string"], + "type": [ + "string" + ], "description": "An ID corresponding to the placement selling the impression" } }, - "required": ["plc"] + "required": [ + "plc" + ] } diff --git a/src/main/resources/static/bidder-params/invibes.json b/src/main/resources/static/bidder-params/invibes.json index 5545b17409d..677698bce5a 100644 --- a/src/main/resources/static/bidder-params/invibes.json +++ b/src/main/resources/static/bidder-params/invibes.json @@ -26,5 +26,7 @@ "description": "Parameters used for debugging purposes" } }, - "required": ["placementId"] + "required": [ + "placementId" + ] } diff --git a/src/main/resources/static/bidder-params/iqzone.json b/src/main/resources/static/bidder-params/iqzone.json index 1a4094f3dfd..404ece4e7ee 100644 --- a/src/main/resources/static/bidder-params/iqzone.json +++ b/src/main/resources/static/bidder-params/iqzone.json @@ -3,7 +3,6 @@ "title": "IQzone Adapter Params", "description": "A schema which validates params accepted by the IQzone adapter", "type": "object", - "properties": { "placementId": { "type": "string", @@ -15,7 +14,15 @@ } }, "oneOf": [ - { "required": ["placementId"] }, - { "required": ["endpointId"] } + { + "required": [ + "placementId" + ] + }, + { + "required": [ + "endpointId" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/ix.json b/src/main/resources/static/bidder-params/ix.json index 172690cca32..28d46d1acf4 100644 --- a/src/main/resources/static/bidder-params/ix.json +++ b/src/main/resources/static/bidder-params/ix.json @@ -35,8 +35,20 @@ } }, "oneOf": [ - {"required": ["siteid"]}, - {"required": ["siteId"]}, - {"required": ["siteID"]} + { + "required": [ + "siteid" + ] + }, + { + "required": [ + "siteId" + ] + }, + { + "required": [ + "siteID" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/jixie.json b/src/main/resources/static/bidder-params/jixie.json index 732b05f8ca7..367c59211c3 100644 --- a/src/main/resources/static/bidder-params/jixie.json +++ b/src/main/resources/static/bidder-params/jixie.json @@ -4,23 +4,25 @@ "description": "A schema which validates params accepted by the Jixie adapter", "type": "object", "properties": { - "unit" : { + "unit": { "type": "string", "description": "The unit code of an inventory target", "minLength": 18 }, - "accountid" : { + "accountid": { "type": "string", "description": "The accountid of an inventory target" }, - "jxprop1" : { + "jxprop1": { "type": "string", "description": "jxprop1 of an inventory target" }, - "jxprop2" : { + "jxprop2": { "type": "string", "description": "jxprop2 of an inventory target" } }, - "required": ["unit"] + "required": [ + "unit" + ] } diff --git a/src/main/resources/static/bidder-params/kayzen.json b/src/main/resources/static/bidder-params/kayzen.json index f2256c6b029..42cccbe667b 100644 --- a/src/main/resources/static/bidder-params/kayzen.json +++ b/src/main/resources/static/bidder-params/kayzen.json @@ -3,7 +3,6 @@ "title": "Kayzen Adapter Params", "description": "A schema which validates params accepted by the Kayzen adapter", "type": "object", - "properties": { "zone": { "type": "string", @@ -16,6 +15,9 @@ "description": "Exchange/Publisher Name" } }, - "required": ["zone", "exchange"] + "required": [ + "zone", + "exchange" + ] } diff --git a/src/main/resources/static/bidder-params/kobler.json b/src/main/resources/static/bidder-params/kobler.json index 7e85601bfe8..567f258c81e 100644 --- a/src/main/resources/static/bidder-params/kobler.json +++ b/src/main/resources/static/bidder-params/kobler.json @@ -3,7 +3,6 @@ "title": "Kobler Adapter Params", "description": "A schema which validates params accepted by the Kobler adapter", "type": "object", - "properties": { "test": { "type": "boolean", diff --git a/src/main/resources/static/bidder-params/krushmedia.json b/src/main/resources/static/bidder-params/krushmedia.json index fcd9e4f419d..da8813866a1 100644 --- a/src/main/resources/static/bidder-params/krushmedia.json +++ b/src/main/resources/static/bidder-params/krushmedia.json @@ -9,5 +9,7 @@ "description": "ssp key" } }, - "required": ["key"] + "required": [ + "key" + ] } diff --git a/src/main/resources/static/bidder-params/logicad.json b/src/main/resources/static/bidder-params/logicad.json index 2a892f91266..2e2e1afca99 100644 --- a/src/main/resources/static/bidder-params/logicad.json +++ b/src/main/resources/static/bidder-params/logicad.json @@ -9,5 +9,7 @@ "description": "Logicad for Publishers placement ID" } }, - "required": ["tid"] + "required": [ + "tid" + ] } diff --git a/src/main/resources/static/bidder-params/loopme.json b/src/main/resources/static/bidder-params/loopme.json index 5ea22ec7ba5..919bef0fe3d 100644 --- a/src/main/resources/static/bidder-params/loopme.json +++ b/src/main/resources/static/bidder-params/loopme.json @@ -20,5 +20,7 @@ "minLength": 1 } }, - "required": ["publisherId"] + "required": [ + "publisherId" + ] } diff --git a/src/main/resources/static/bidder-params/lunamedia.json b/src/main/resources/static/bidder-params/lunamedia.json index 1aa18cee6b9..ec1b2b67b2e 100644 --- a/src/main/resources/static/bidder-params/lunamedia.json +++ b/src/main/resources/static/bidder-params/lunamedia.json @@ -14,5 +14,7 @@ "description": "A placement created on adserver." } }, - "required": ["pubid"] + "required": [ + "pubid" + ] } diff --git a/src/main/resources/static/bidder-params/mabidder.json b/src/main/resources/static/bidder-params/mabidder.json index 0c39c66fbc9..b5d24cb8155 100644 --- a/src/main/resources/static/bidder-params/mabidder.json +++ b/src/main/resources/static/bidder-params/mabidder.json @@ -9,5 +9,7 @@ "description": "Publisher Placement ID" } }, - "required": ["ppid"] + "required": [ + "ppid" + ] } diff --git a/src/main/resources/static/bidder-params/magnite.json b/src/main/resources/static/bidder-params/magnite.json index 5f0ea8ea33e..4b4d9ded3fc 100644 --- a/src/main/resources/static/bidder-params/magnite.json +++ b/src/main/resources/static/bidder-params/magnite.json @@ -62,11 +62,17 @@ "description": "Language of the ad - should match content video" }, "playerHeight": { - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "description": "Height in pixels of the video player" }, "playerWidth": { - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "description": "Width in pixels of the video player" }, "size_id": { diff --git a/src/main/resources/static/bidder-params/mediago.json b/src/main/resources/static/bidder-params/mediago.json index a4fcb3b5392..685d2b70b4d 100644 --- a/src/main/resources/static/bidder-params/mediago.json +++ b/src/main/resources/static/bidder-params/mediago.json @@ -11,7 +11,11 @@ }, "region": { "type": "string", - "enum": ["US", "EU", "APAC"], + "enum": [ + "US", + "EU", + "APAC" + ], "description": "Server region for PBS request: US for US Region, EU for EU Region, APAC for APAC Region, default is US. This parameter expects all imps to be the same" }, "placementId": { @@ -20,5 +24,7 @@ "minLength": 1 } }, - "required": ["token"] + "required": [ + "token" + ] } diff --git a/src/main/resources/static/bidder-params/mgid.json b/src/main/resources/static/bidder-params/mgid.json index cd83dd644f7..dbecb6dafe2 100644 --- a/src/main/resources/static/bidder-params/mgid.json +++ b/src/main/resources/static/bidder-params/mgid.json @@ -29,5 +29,7 @@ "description": "optional minimum acceptable bid, in CPM, USD by default" } }, - "required": ["accountId"] + "required": [ + "accountId" + ] } diff --git a/src/main/resources/static/bidder-params/missena.json b/src/main/resources/static/bidder-params/missena.json index be5217efdb1..9dd4fabd77c 100644 --- a/src/main/resources/static/bidder-params/missena.json +++ b/src/main/resources/static/bidder-params/missena.json @@ -13,9 +13,12 @@ "type": "string", "description": "Placement Type (Sticky, Header, ...)" }, - "test": { - "type": "string", - "description": "Test Mode" + "sample": { + "type": [ + "string", + "null" + ], + "description": "Sample" }, "formats": { "type": "array", diff --git a/src/main/resources/static/bidder-params/nativery.json b/src/main/resources/static/bidder-params/nativery.json index 9f8dc02c274..36f7e34e4ec 100644 --- a/src/main/resources/static/bidder-params/nativery.json +++ b/src/main/resources/static/bidder-params/nativery.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Nativery Adapter Params", "description": "A schema which validates params accepted by the Nativery adapter", - "type": "object", "properties": { "widgetId": { @@ -10,6 +9,7 @@ "description": "An ID which identifies this Nativery widget" } }, - - "required": ["widgetId"] + "required": [ + "widgetId" + ] } diff --git a/src/main/resources/static/bidder-params/nativo.json b/src/main/resources/static/bidder-params/nativo.json index d25ec75f3bc..69d99ac2bc4 100644 --- a/src/main/resources/static/bidder-params/nativo.json +++ b/src/main/resources/static/bidder-params/nativo.json @@ -5,7 +5,10 @@ "type": "object", "properties": { "placementId": { - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "description": "Placement ID" } } diff --git a/src/main/resources/static/bidder-params/nobid.json b/src/main/resources/static/bidder-params/nobid.json index 058df39ecb1..e3bade03a6c 100644 --- a/src/main/resources/static/bidder-params/nobid.json +++ b/src/main/resources/static/bidder-params/nobid.json @@ -2,16 +2,18 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "NoBid Adapter Params", "description": "A schema which validates params accepted by the NoBid adapter", - "type": "object", "properties": { "siteId": { "type": "integer", "description": "A Required ID which identifies the NoBid site. The siteId parameter is provided by your NoBid account manager." - }, "placementId": { + }, + "placementId": { "type": "integer", "description": "An optional ID which identifies an adunit in a site. The placementId parameter is provided by your NoBid account manager." } }, - "required": ["siteId"] + "required": [ + "siteId" + ] } diff --git a/src/main/resources/static/bidder-params/onetag.json b/src/main/resources/static/bidder-params/onetag.json index a1c22869a7b..c7a34503552 100644 --- a/src/main/resources/static/bidder-params/onetag.json +++ b/src/main/resources/static/bidder-params/onetag.json @@ -3,7 +3,6 @@ "title": "Onetag Adapter Params", "description": "A schema which validates params accepted by the Onetag adapter", "type": "object", - "properties": { "pubId": { "type": "string", @@ -15,6 +14,7 @@ "description": "A set of custom key-value pairs" } }, - - "required": ["pubId"] + "required": [ + "pubId" + ] } diff --git a/src/main/resources/static/bidder-params/openx.json b/src/main/resources/static/bidder-params/openx.json index 89c0663e0a0..e1d9025b64f 100644 --- a/src/main/resources/static/bidder-params/openx.json +++ b/src/main/resources/static/bidder-params/openx.json @@ -2,11 +2,13 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Openx Adapter Params", "description": "A schema which validates params accepted by the Openx adapter", - "type": "object", "properties": { "unit": { - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "description": "The ad unit id.", "pattern": "^[0-9]+$" }, @@ -22,7 +24,10 @@ "format": "uuid" }, "customFloor": { - "type": ["number", "string"], + "type": [ + "number", + "string" + ], "description": "The minimum CPM price in USD.", "minimum": 0, "pattern": "^[0-9]+(\\.[0-9]+)?$" diff --git a/src/main/resources/static/bidder-params/orbidder.json b/src/main/resources/static/bidder-params/orbidder.json index d986b23284e..d8aab7010ca 100644 --- a/src/main/resources/static/bidder-params/orbidder.json +++ b/src/main/resources/static/bidder-params/orbidder.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Orbidder Adapter Params", "description": "A schema which validates params accepted by the Orbidder adapter", - "type": "object", "properties": { "accountId": { @@ -19,6 +18,8 @@ "minimum": 0 } }, - - "required": ["accountId", "placementId"] -} \ No newline at end of file + "required": [ + "accountId", + "placementId" + ] +} diff --git a/src/main/resources/static/bidder-params/outbrain.json b/src/main/resources/static/bidder-params/outbrain.json index 8cfb8bbdf28..65ccc3d6ac0 100644 --- a/src/main/resources/static/bidder-params/outbrain.json +++ b/src/main/resources/static/bidder-params/outbrain.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Outbrain Adapter Params", "description": "A schema which validates params accepted by the Outbrain adapter", - "type": "object", "properties": { "publisher": { @@ -18,7 +17,9 @@ "type": "string" } }, - "required": ["id"] + "required": [ + "id" + ] }, "tagid": { "type": "string" @@ -36,5 +37,7 @@ } } }, - "required": ["publisher"] + "required": [ + "publisher" + ] } diff --git a/src/main/resources/static/bidder-params/pgamssp.json b/src/main/resources/static/bidder-params/pgamssp.json index f8204494c8e..582afe8a03d 100644 --- a/src/main/resources/static/bidder-params/pgamssp.json +++ b/src/main/resources/static/bidder-params/pgamssp.json @@ -3,7 +3,6 @@ "title": "PgamSSP Adapter Params", "description": "A schema which validates params accepted by the PgamSSP adapter", "type": "object", - "properties": { "placementId": { "type": "string", @@ -17,7 +16,15 @@ } }, "oneOf": [ - { "required": ["placementId"] }, - { "required": ["endpointId"] } + { + "required": [ + "placementId" + ] + }, + { + "required": [ + "endpointId" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/preciso.json b/src/main/resources/static/bidder-params/preciso.json index fa87307cf08..71e05235316 100644 --- a/src/main/resources/static/bidder-params/preciso.json +++ b/src/main/resources/static/bidder-params/preciso.json @@ -9,5 +9,7 @@ "description": "An ID which identifies the publisher" } }, - "required": ["publisherId"] + "required": [ + "publisherId" + ] } diff --git a/src/main/resources/static/bidder-params/pwbid.json b/src/main/resources/static/bidder-params/pwbid.json index 93aea89f9c1..ac4161bd056 100644 --- a/src/main/resources/static/bidder-params/pwbid.json +++ b/src/main/resources/static/bidder-params/pwbid.json @@ -17,5 +17,7 @@ "description": "A boolean to indicate 100% fill test placement request" } }, - "required": ["siteId"] + "required": [ + "siteId" + ] } diff --git a/src/main/resources/static/bidder-params/readpeak.json b/src/main/resources/static/bidder-params/readpeak.json index 274aadb92e0..9ec2bf755d5 100644 --- a/src/main/resources/static/bidder-params/readpeak.json +++ b/src/main/resources/static/bidder-params/readpeak.json @@ -21,5 +21,7 @@ "description": "Ad placement identifier" } }, - "required": ["publisherId"] + "required": [ + "publisherId" + ] } diff --git a/src/main/resources/static/bidder-params/resetdigital.json b/src/main/resources/static/bidder-params/resetdigital.json index dc79816ce68..fe529d42b34 100644 --- a/src/main/resources/static/bidder-params/resetdigital.json +++ b/src/main/resources/static/bidder-params/resetdigital.json @@ -10,6 +10,8 @@ "minLength": 1 } }, - "required": ["placement_id"], + "required": [ + "placement_id" + ], "additionalProperties": false } diff --git a/src/main/resources/static/bidder-params/rtbhouse.json b/src/main/resources/static/bidder-params/rtbhouse.json index 431422ca756..a2091295c34 100644 --- a/src/main/resources/static/bidder-params/rtbhouse.json +++ b/src/main/resources/static/bidder-params/rtbhouse.json @@ -9,5 +9,7 @@ "description": "The publisher's ID provided by RTB House" } }, - "required": ["publisherId"] + "required": [ + "publisherId" + ] } diff --git a/src/main/resources/static/bidder-params/scalibur.json b/src/main/resources/static/bidder-params/scalibur.json new file mode 100644 index 00000000000..56037ad7e0f --- /dev/null +++ b/src/main/resources/static/bidder-params/scalibur.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Scalibur Adapter Params", + "description": "A valid BidderParams object for the Scalibur adapter. Every impression must resolve a placement: either set placementId here, or set imp.tagid on the ad unit. An impression with neither is not served.", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "description": "Placement id, applied to imp.tagid. Optional: may instead be supplied per ad unit as imp.tagid. At least one source must resolve or the imp is not served.", + "minLength": 1 + }, + "bidfloor": { + "type": "number", + "description": "The minimum price acceptable for a bid", + "minimum": 0 + }, + "bidfloorcur": { + "type": "string", + "description": "currency floor price" + }, + "host": { + "type": "string", + "description": "Subdomain label of the scalibur.io endpoint, for account or environment specific servers. A single RFC 1123 DNS label only, no dots or port; the domain itself is fixed. Defaults to srv. Impressions naming different subdomains are sent as separate requests, one per subdomain.", + "pattern": "^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$" + } + } +} diff --git a/src/main/resources/static/bidder-params/seedtag.json b/src/main/resources/static/bidder-params/seedtag.json index 4e09dd7eb69..9c0ce2b4c4d 100644 --- a/src/main/resources/static/bidder-params/seedtag.json +++ b/src/main/resources/static/bidder-params/seedtag.json @@ -4,24 +4,35 @@ "description": "A schema which validates params accepted by the Seedtag adapter", "type": "object", "properties": { - "adUnitId": { - "type": "string", - "description": "Ad Unit ID", - "minLength": 1 - }, - "publisherId": { - "type": "string", - "description": "Publisher ID (editorial group ID)", - "minLength": 1 - }, - "integrationType": { - "type": "string", - "description": "Integration type", - "enum": ["ronId"] - } + "adUnitId": { + "type": "string", + "description": "Ad Unit ID", + "minLength": 1 + }, + "publisherId": { + "type": "string", + "description": "Publisher ID (editorial group ID)", + "minLength": 1 + }, + "integrationType": { + "type": "string", + "description": "Integration type", + "enum": [ + "ronId" + ] + } }, "oneOf": [ - { "required": ["adUnitId"] }, - { "required": ["publisherId", "integrationType"] } + { + "required": [ + "adUnitId" + ] + }, + { + "required": [ + "publisherId", + "integrationType" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/sevio.json b/src/main/resources/static/bidder-params/sevio.json new file mode 100644 index 00000000000..da0992cc359 --- /dev/null +++ b/src/main/resources/static/bidder-params/sevio.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Sevio Adapter Params", + "description": "A schema which validates params accepted by the Sevio adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "minLength": 1, + "description": "Placement Id or Zone Id" + } + }, + "required": [ + "placementId" + ] +} diff --git a/src/main/resources/static/bidder-params/sharethrough.json b/src/main/resources/static/bidder-params/sharethrough.json index f1357e9133f..922587602c5 100644 --- a/src/main/resources/static/bidder-params/sharethrough.json +++ b/src/main/resources/static/bidder-params/sharethrough.json @@ -25,5 +25,7 @@ "description": "Blocked IAB Categories" } }, - "required": ["pkey"] + "required": [ + "pkey" + ] } diff --git a/src/main/resources/static/bidder-params/showheroes.json b/src/main/resources/static/bidder-params/showheroes.json index 3c269d118d8..48ae7a07d97 100644 --- a/src/main/resources/static/bidder-params/showheroes.json +++ b/src/main/resources/static/bidder-params/showheroes.json @@ -10,5 +10,7 @@ "minLength": 8 } }, - "required": ["unitId"] + "required": [ + "unitId" + ] } diff --git a/src/main/resources/static/bidder-params/silvermob.json b/src/main/resources/static/bidder-params/silvermob.json index 0ded8714cb5..13f8edc1a27 100644 --- a/src/main/resources/static/bidder-params/silvermob.json +++ b/src/main/resources/static/bidder-params/silvermob.json @@ -13,5 +13,8 @@ "description": "Host" } }, - "required": ["zoneid", "host"] + "required": [ + "zoneid", + "host" + ] } diff --git a/src/main/resources/static/bidder-params/smartadserver.json b/src/main/resources/static/bidder-params/smartadserver.json index 28685276bde..b9b28c7588b 100644 --- a/src/main/resources/static/bidder-params/smartadserver.json +++ b/src/main/resources/static/bidder-params/smartadserver.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Smartadserver Adapter Params", "description": "A schema which validates params accepted by the Smartadserver adapter", - "type": "object", "properties": { "siteId": { @@ -27,9 +26,26 @@ } }, "dependencies": { - "siteId": { "required": ["pageId", "formatId"] }, - "pageId": { "required": ["siteId", "formatId"] }, - "formatId": { "required": ["siteId", "pageId"] } + "siteId": { + "required": [ + "pageId", + "formatId" + ] + }, + "pageId": { + "required": [ + "siteId", + "formatId" + ] + }, + "formatId": { + "required": [ + "siteId", + "pageId" + ] + } }, - "required": ["networkId"] + "required": [ + "networkId" + ] } diff --git a/src/main/resources/static/bidder-params/smartrtb.json b/src/main/resources/static/bidder-params/smartrtb.json index 46bccb7468b..0ab12cfb5e2 100644 --- a/src/main/resources/static/bidder-params/smartrtb.json +++ b/src/main/resources/static/bidder-params/smartrtb.json @@ -23,5 +23,7 @@ "description": "Force bids with a test creative" } }, - "required": [ "pub_id" ] + "required": [ + "pub_id" + ] } diff --git a/src/main/resources/static/bidder-params/smartyads.json b/src/main/resources/static/bidder-params/smartyads.json index f86a2e4b66b..7bce345aac0 100644 --- a/src/main/resources/static/bidder-params/smartyads.json +++ b/src/main/resources/static/bidder-params/smartyads.json @@ -17,5 +17,9 @@ "description": "Account id" } }, - "required": ["host", "sourceid", "accountid"] + "required": [ + "host", + "sourceid", + "accountid" + ] } diff --git a/src/main/resources/static/bidder-params/smilewanted.json b/src/main/resources/static/bidder-params/smilewanted.json index be4f9bc142d..fcfb87a160e 100644 --- a/src/main/resources/static/bidder-params/smilewanted.json +++ b/src/main/resources/static/bidder-params/smilewanted.json @@ -10,5 +10,7 @@ "minLength": 1 } }, - "required": ["zoneId"] + "required": [ + "zoneId" + ] } diff --git a/src/main/resources/static/bidder-params/smrtconnect.json b/src/main/resources/static/bidder-params/smrtconnect.json index 74229a46133..7b75dfbeaff 100644 --- a/src/main/resources/static/bidder-params/smrtconnect.json +++ b/src/main/resources/static/bidder-params/smrtconnect.json @@ -10,5 +10,7 @@ "minLength": 1 } }, - "required": ["supply_id"] + "required": [ + "supply_id" + ] } diff --git a/src/main/resources/static/bidder-params/sovrn.json b/src/main/resources/static/bidder-params/sovrn.json index 4f779a9f1f6..279d836c62c 100644 --- a/src/main/resources/static/bidder-params/sovrn.json +++ b/src/main/resources/static/bidder-params/sovrn.json @@ -30,7 +30,15 @@ } }, "oneOf": [ - { "required" : [ "tagid" ] }, - { "required" : [ "tagId" ] } + { + "required": [ + "tagid" + ] + }, + { + "required": [ + "tagId" + ] + } ] } diff --git a/src/main/resources/static/bidder-params/sovrnXsp.json b/src/main/resources/static/bidder-params/sovrnXsp.json index a6c35ee2504..ea45e0fb83f 100644 --- a/src/main/resources/static/bidder-params/sovrnXsp.json +++ b/src/main/resources/static/bidder-params/sovrnXsp.json @@ -23,5 +23,7 @@ "description": "Force bids with a test creative" } }, - "required": [ "pub_id" ] + "required": [ + "pub_id" + ] } diff --git a/src/main/resources/static/bidder-params/sparteo.json b/src/main/resources/static/bidder-params/sparteo.json index ca8c072ae77..ff236e0b22a 100644 --- a/src/main/resources/static/bidder-params/sparteo.json +++ b/src/main/resources/static/bidder-params/sparteo.json @@ -1,34 +1,34 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Sparteo Params", - "type": "object", - "properties": { - "networkId": { - "type": "string", - "description": "Sparteo network ID. This information will be given to you by the Sparteo team." - }, - "custom1": { - "type": "string", - "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." - }, - "custom2": { - "type": "string", - "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." - }, - "custom3": { - "type": "string", - "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." - }, - "custom4": { - "type": "string", - "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." - }, - "custom5": { - "type": "string", - "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." - } + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Sparteo Params", + "type": "object", + "properties": { + "networkId": { + "type": "string", + "description": "Sparteo network ID. This information will be given to you by the Sparteo team." }, - "required": [ - "networkId" - ] -} \ No newline at end of file + "custom1": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + }, + "custom2": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + }, + "custom3": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + }, + "custom4": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + }, + "custom5": { + "type": "string", + "description": "To be used in reporting. Alphanumeric strings ; case sensitive ; max 40 characters ; only allowed symbols are hyphen and underscore." + } + }, + "required": [ + "networkId" + ] +} diff --git a/src/main/resources/static/bidder-params/synapsehx.json b/src/main/resources/static/bidder-params/synapsehx.json new file mode 100644 index 00000000000..53382eb6e45 --- /dev/null +++ b/src/main/resources/static/bidder-params/synapsehx.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Synapse HX Adapter Params", + "description": "A schema which validates params accepted by the Synapse HX adapter", + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "description": "Synapse HX tenant identifier", + "minLength": 1 + } + }, + "required": [ + "tenantId" + ] +} diff --git a/src/main/resources/static/bidder-params/taboola.json b/src/main/resources/static/bidder-params/taboola.json index 25c126603ab..76b3ea1b69f 100644 --- a/src/main/resources/static/bidder-params/taboola.json +++ b/src/main/resources/static/bidder-params/taboola.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Taboola Adapter Params", "description": "A schema which validates params accepted by the Taboola adapter", - "type": "object", "properties": { "publisherId": { @@ -43,10 +42,16 @@ }, "oneOf": [ { - "required": [ "tagid", "publisherId" ] + "required": [ + "tagid", + "publisherId" + ] }, { - "required": [ "tagId", "publisherId" ] + "required": [ + "tagId", + "publisherId" + ] } ] } diff --git a/src/main/resources/static/bidder-params/thetradedesk.json b/src/main/resources/static/bidder-params/thetradedesk.json index 566e7e556e6..fe01e895848 100644 --- a/src/main/resources/static/bidder-params/thetradedesk.json +++ b/src/main/resources/static/bidder-params/thetradedesk.json @@ -10,10 +10,12 @@ "description": "An ID which identifies the publisher" }, "supplySourceId": { - "type":"string", + "type": "string", "minLength": 1, "description": "An ID provided by TheTradeDesk used to determine which endpoint to use" } }, - "required": ["publisherId"] + "required": [ + "publisherId" + ] } diff --git a/src/main/resources/static/bidder-params/trafficgate.json b/src/main/resources/static/bidder-params/trafficgate.json index 8b7ff3bee3b..07c1487a3b5 100644 --- a/src/main/resources/static/bidder-params/trafficgate.json +++ b/src/main/resources/static/bidder-params/trafficgate.json @@ -19,5 +19,8 @@ "description": "User-defined targeting key-value pairs." } }, - "required" : [ "placementId", "host" ] + "required": [ + "placementId", + "host" + ] } diff --git a/src/main/resources/static/bidder-params/triplelift.json b/src/main/resources/static/bidder-params/triplelift.json index 3eebd0f33af..ff92cd9375a 100644 --- a/src/main/resources/static/bidder-params/triplelift.json +++ b/src/main/resources/static/bidder-params/triplelift.json @@ -13,5 +13,7 @@ "description": "the bid floor" } }, - "required": ["inventoryCode"] + "required": [ + "inventoryCode" + ] } diff --git a/src/main/resources/static/bidder-params/triplelift_native.json b/src/main/resources/static/bidder-params/triplelift_native.json index 4cf90ef49e7..550d3b605f9 100644 --- a/src/main/resources/static/bidder-params/triplelift_native.json +++ b/src/main/resources/static/bidder-params/triplelift_native.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Triplelift Adapter Params", "description": "A schema which validates params accepted by the Triplelift adapter", - "type": "object", "properties": { "inventoryCode": { @@ -10,7 +9,12 @@ "minLength": 1, "description": "TripleLift inventory code for this ad unit (provided to you by your partner manager)" }, - "floor" : {"description" : "the bid floor, in usd", "type": "number" } + "floor": { + "description": "the bid floor, in usd", + "type": "number" + } }, - "required": ["inventoryCode"] + "required": [ + "inventoryCode" + ] } diff --git a/src/main/resources/static/bidder-params/ucfunnel.json b/src/main/resources/static/bidder-params/ucfunnel.json index d3e8af07ed5..c60e10cbb4f 100644 --- a/src/main/resources/static/bidder-params/ucfunnel.json +++ b/src/main/resources/static/bidder-params/ucfunnel.json @@ -13,5 +13,7 @@ "description": "ID for partner" } }, - "required": ["partnerid"] + "required": [ + "partnerid" + ] } diff --git a/src/main/resources/static/bidder-params/unicorn.json b/src/main/resources/static/bidder-params/unicorn.json index 247b39300eb..071869dd8a8 100644 --- a/src/main/resources/static/bidder-params/unicorn.json +++ b/src/main/resources/static/bidder-params/unicorn.json @@ -21,5 +21,7 @@ "description": "Account ID for charge request" } }, - "required" : ["accountId"] + "required": [ + "accountId" + ] } diff --git a/src/main/resources/static/bidder-params/unruly.json b/src/main/resources/static/bidder-params/unruly.json index 3c698a19cfa..57b3a2825f9 100644 --- a/src/main/resources/static/bidder-params/unruly.json +++ b/src/main/resources/static/bidder-params/unruly.json @@ -13,13 +13,16 @@ "description": "ID for publisher site" } }, - "oneOf": [ { - "required": ["siteId"] + "required": [ + "siteId" + ] }, { - "required": ["siteid"] + "required": [ + "siteid" + ] } ] } diff --git a/src/main/resources/static/bidder-params/visx.json b/src/main/resources/static/bidder-params/visx.json index fe606f93000..34276b11cd5 100644 --- a/src/main/resources/static/bidder-params/visx.json +++ b/src/main/resources/static/bidder-params/visx.json @@ -5,7 +5,10 @@ "type": "object", "properties": { "uid": { - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "pattern": "^\\d+$", "description": "An ID which identifies this placement of the impression" }, @@ -19,5 +22,7 @@ "description": "An array of two integer containing the dimension" } }, - "required": ["uid"] + "required": [ + "uid" + ] } diff --git a/src/main/resources/static/bidder-params/vox.json b/src/main/resources/static/bidder-params/vox.json index eaecdca8a12..e74874b6fd1 100644 --- a/src/main/resources/static/bidder-params/vox.json +++ b/src/main/resources/static/bidder-params/vox.json @@ -3,7 +3,6 @@ "title": "Vox Adapter Params", "description": "A schema which validates params accepted by the Vox adapter", "type": "object", - "properties": { "placementId": { "type": "string", @@ -22,6 +21,7 @@ "description": "Display banner sizes which could be shown on top of image." } }, - - "required": ["placementId"] + "required": [ + "placementId" + ] } diff --git a/src/main/resources/static/bidder-params/yeahmobi.json b/src/main/resources/static/bidder-params/yeahmobi.json index 07bf751e17f..8e3829eac21 100644 --- a/src/main/resources/static/bidder-params/yeahmobi.json +++ b/src/main/resources/static/bidder-params/yeahmobi.json @@ -15,5 +15,8 @@ "minLength": 1 } }, - "required": ["pubId", "zoneId"] + "required": [ + "pubId", + "zoneId" + ] } diff --git a/src/main/resources/static/bidder-params/yearxero.json b/src/main/resources/static/bidder-params/yearxero.json index 9b1d1153e71..5f3581b74ba 100644 --- a/src/main/resources/static/bidder-params/yearxero.json +++ b/src/main/resources/static/bidder-params/yearxero.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Yearxero Adapter Params", "description": "A schema which validates params accepted by the YearXero adapter", - "type": "object", "properties": { "customParams": { diff --git a/src/main/resources/static/bidder-params/zeroclickfraud.json b/src/main/resources/static/bidder-params/zeroclickfraud.json index 5545b6180c0..ef7e2684454 100644 --- a/src/main/resources/static/bidder-params/zeroclickfraud.json +++ b/src/main/resources/static/bidder-params/zeroclickfraud.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "ZeroClickFraud Adapter Params", "description": "A schema which validates params accepted by the ZeroClickFraud adapter", - "type": "object", "properties": { "sourceId": { @@ -15,5 +14,8 @@ "description": "Network Host to request from" } }, - "required": ["host", "sourceId"] + "required": [ + "host", + "sourceId" + ] } diff --git a/src/main/resources/static/bidder-params/zeta_global_ssp.json b/src/main/resources/static/bidder-params/zeta_global_ssp.json index 91ff05ed089..3c2386431e8 100644 --- a/src/main/resources/static/bidder-params/zeta_global_ssp.json +++ b/src/main/resources/static/bidder-params/zeta_global_ssp.json @@ -3,8 +3,6 @@ "title": "Zeta Global SSP Adapter Params", "description": "A schema which validates params accepted by the Zeta SSP adapter", "type": "object", - "properties": {}, - "required": [] } diff --git a/src/main/resources/static/pbs_request.json b/src/main/resources/static/pbs_request.json index edf9fbca80e..bbfa9cc8f08 100644 --- a/src/main/resources/static/pbs_request.json +++ b/src/main/resources/static/pbs_request.json @@ -1,408 +1,408 @@ { - "id": "http://prebid.org/pbs_request.json", - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "schema for a Prebid Server request", - "type": "object", - "required": [ - "account_id", - "ad_units" - ], - "properties": { - "account_id": { - "type": "string" + "id": "http://prebid.org/pbs_request.json", + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "schema for a Prebid Server request", + "type": "object", + "required": [ + "account_id", + "ad_units" + ], + "properties": { + "account_id": { + "type": "string" + }, + "tid": { + "description": "Unique transaction ID", + "type": "string" + }, + "timeout_millis": { + "description": "How long to wait for adapters to return bids", + "type": "integer" + }, + "secure": { + "description": "Flag to indicate if the impression requires secure HTTPS URL creative assets and markup, where 0 = non-secure, 1 = secure. If omitted, the secure state will be interpreted from the request to the prebid server", + "type": "integer" + }, + "cache_markup": { + "description": "Caches markup for two-phase response (get response then separate call to get markup)", + "type": "integer" + }, + "sort_bids": { + "description": "Sorts bids by price & response time and returns ad server targeting keys for each bid in prebid server response", + "type": "integer" + }, + "max_key_length": { + "description": "Used to determine whether ad server targeting key strings should be truncated on prebid server. For DFP max key length should be 20.", + "type": "integer" + }, + "app": { + "type": "object", + "description": "This object should be included if the ad supported content is a non-browser application (typically in mobile) as opposed to a website. At a minimum, it is useful to provide an App ID or bundle, but this is not strictly required.", + "properties": { + "name": { + "description": "App name (may be aliased at the publisher’s request).", + "type": "string" }, - "tid": { - "description": "Unique transaction ID", - "type": "string" + "bundle": { + "description": "A platform-specific application identifier intended to be unique to the app and independent of the exchange. On Android, this should be a bundle or package name (e.g., com.foo.mygame). On iOS, it is typically a numeric ID.", + "type": "string" }, - "timeout_millis": { - "description": "How long to wait for adapters to return bids", - "type": "integer" + "domain": { + "description": "Domain of the app (e.g., 'mygame.foo.com').", + "type": "string" }, - "secure": { - "description": "Flag to indicate if the impression requires secure HTTPS URL creative assets and markup, where 0 = non-secure, 1 = secure. If omitted, the secure state will be interpreted from the request to the prebid server", - "type": "integer" + "storeurl": { + "description": "App store URL for an installed app; for IQG 2.1 compliance.", + "type": "string" }, - "cache_markup": { - "description": "Caches markup for two-phase response (get response then separate call to get markup)", - "type": "integer" + "ver": { + "description": "Application version.", + "type": "string" }, - "sort_bids": { - "description": "Sorts bids by price & response time and returns ad server targeting keys for each bid in prebid server response", - "type": "integer" + "privacypolicy": { + "description": "Indicates if the app has a privacy policy, where 0 = no, 1 = yes.", + "type": "integer" }, - "max_key_length": { - "description": "Used to determine whether ad server targeting key strings should be truncated on prebid server. For DFP max key length should be 20.", - "type": "integer" + "paid": { + "description": "0 = app is free, 1 = the app is a paid version.", + "type": "integer" }, - "app": { - "type": "object", - "description": "This object should be included if the ad supported content is a non-browser application (typically in mobile) as opposed to a website. At a minimum, it is useful to provide an App ID or bundle, but this is not strictly required.", - "properties": { - "name": { - "description": "App name (may be aliased at the publisher’s request).", - "type": "string" - }, - "bundle": { - "description": "A platform-specific application identifier intended to be unique to the app and independent of the exchange. On Android, this should be a bundle or package name (e.g., com.foo.mygame). On iOS, it is typically a numeric ID.", - "type": "string" - }, - "domain": { - "description": "Domain of the app (e.g., 'mygame.foo.com').", - "type": "string" - }, - "storeurl": { - "description": "App store URL for an installed app; for IQG 2.1 compliance.", - "type": "string" - }, - "ver": { - "description": "Application version.", - "type": "string" - }, - "privacypolicy": { - "description": "Indicates if the app has a privacy policy, where 0 = no, 1 = yes.", - "type": "integer" - }, - "paid": { - "description": "0 = app is free, 1 = the app is a paid version.", - "type": "integer" - }, - "keywords": { - "description": "Comma separated list of keywords about the app.", - "type": "string" - } + "keywords": { + "description": "Comma separated list of keywords about the app.", + "type": "string" + } + } + }, + "device": { + "type": "object", + "description": "3.2.18 Object: Device. This object provides information pertaining to the device through which the user is interacting. Device information includes its hardware, platform, location, and carrier data. The device can refer to a mobile handset, a desktop computer, set top box, or other digital device.", + "properties": { + "ua": { + "description": "Browser user agent string.", + "type": "string" + }, + "geo": { + "type": "object", + "description": "This object encapsulates various methods for specifying a geographic location. When subordinate to a Device object, it indicates the location of the device which can also be interpreted as the user’s current location. The lat/lon attributes should only be passed if they conform to the accuracy depicted in the type attribute. For example, the centroid of a geographic region such as postal code should not be passed.", + "properties": { + "lat": { + "description": "Latitude from -90.0 to +90.0, where negative is south.", + "type": "number" + }, + "lon": { + "description": "Longitude from -180.0 to +180.0, where negative is west.", + "type": "number" + }, + "type": { + "description": "Source of location data; recommended when passing lat/lon. Refer to List 5.20.", + "type": "integer" + }, + "accuracy": { + "description": "Estimated location accuracy in meters; recommended when lat/lon are specified and derived from a device’s location services (i.e., type = 1). Note that this is the accuracy as reported from the device. Consult OS specific documentation (e.g., Android, iOS) for exact interpretation.", + "type": "integer" + }, + "lastfix": { + "description": "Number of seconds since this geolocation fix was established. Note that devices may cache location data across multiple fetches. Ideally, this value should be from the time the actual fix was taken.", + "type": "integer" + }, + "ipservice": { + "description": "Service or provider used to determine geolocation from IP address if applicable (i.e., type = 2). Refer to List 5.23.", + "type": "integer" + }, + "country": { + "description": "Country code using ISO-3166-1-alpha-3.", + "type": "string" + }, + "region": { + "description": "Region code using ISO-3166-2; 2-letter state code if USA.", + "type": "string" + }, + "metro": { + "description": "Google metro code; similar to but not exactly Nielsen DMAs. See Appendix A for a link to the codes.", + "type": "string" + }, + "city": { + "description": "City using United Nations Code for Trade & Transport Locations. See Appendix A for a link to the codes.", + "type": "string" + }, + "zip": { + "description": "Zip or postal code.", + "type": "string" + }, + "utcoffset": { + "description": "Local time as the number +/- of minutes from UTC.", + "type": "string" } + } }, - "device": { - "type": "object", - "description": "3.2.18 Object: Device. This object provides information pertaining to the device through which the user is interacting. Device information includes its hardware, platform, location, and carrier data. The device can refer to a mobile handset, a desktop computer, set top box, or other digital device.", - "properties": { - "ua": { - "description": "Browser user agent string.", - "type": "string" - }, - "geo": { - "type": "object", - "description": "This object encapsulates various methods for specifying a geographic location. When subordinate to a Device object, it indicates the location of the device which can also be interpreted as the user’s current location. The lat/lon attributes should only be passed if they conform to the accuracy depicted in the type attribute. For example, the centroid of a geographic region such as postal code should not be passed.", - "properties": { - "lat": { - "description": "Latitude from -90.0 to +90.0, where negative is south.", - "type": "number" - }, - "lon": { - "description": "Longitude from -180.0 to +180.0, where negative is west.", - "type": "number" - }, - "type": { - "description": "Source of location data; recommended when passing lat/lon. Refer to List 5.20.", - "type": "integer" - }, - "accuracy": { - "description": "Estimated location accuracy in meters; recommended when lat/lon are specified and derived from a device’s location services (i.e., type = 1). Note that this is the accuracy as reported from the device. Consult OS specific documentation (e.g., Android, iOS) for exact interpretation.", - "type": "integer" - }, - "lastfix": { - "description": "Number of seconds since this geolocation fix was established. Note that devices may cache location data across multiple fetches. Ideally, this value should be from the time the actual fix was taken.", - "type": "integer" - }, - "ipservice": { - "description": "Service or provider used to determine geolocation from IP address if applicable (i.e., type = 2). Refer to List 5.23.", - "type": "integer" - }, - "country": { - "description": "Country code using ISO-3166-1-alpha-3.", - "type": "string" - }, - "region": { - "description": "Region code using ISO-3166-2; 2-letter state code if USA.", - "type": "string" - }, - "metro": { - "description": "Google metro code; similar to but not exactly Nielsen DMAs. See Appendix A for a link to the codes.", - "type": "string" - }, - "city": { - "description": "City using United Nations Code for Trade & Transport Locations. See Appendix A for a link to the codes.", - "type": "string" - }, - "zip": { - "description": "Zip or postal code.", - "type": "string" - }, - "utcoffset": { - "description": "Local time as the number +/- of minutes from UTC.", - "type": "string" - } - } - }, - "dnt": { - "description": "Standard “Do Not Track” flag as set in the header by the browser, where 0 = tracking is unrestricted, 1 = do not track.", - "type": "integer" - }, - "lmt": { - "description": "'Limit Ad Tracking' signal commercially endorsed (e.g., iOS, Android), where 0 = tracking is unrestricted, 1 = tracking must be limited per commercial guidelines.", - "type": "integer" - }, - "ip": { - "description": "IPv4 address closest to device.", - "type": "string" - }, - "ipv6": { - "description": "IPv6 address closest to device.", - "type": "string" - }, - "devicetype": { - "description": "The general type of device. Refer to List 5.21.", - "type": "integer" - }, - "make": { - "description": "Device make (e.g., 'Apple').", - "type": "string" - }, - "model": { - "description": "Device model (e.g., 'iPhone')", - "type": "string" - }, - "os": { - "description": "Device operating system (e.g., 'iOS').", - "type": "string" - }, - "osv": { - "description": "Device operating system version (e.g., '3.1.2').", - "type": "string" - }, - "hwv": { - "description": "Hardware version of the device (e.g., '5S' for iPhone 5S).", - "type": "string" - }, + "dnt": { + "description": "Standard “Do Not Track” flag as set in the header by the browser, where 0 = tracking is unrestricted, 1 = do not track.", + "type": "integer" + }, + "lmt": { + "description": "'Limit Ad Tracking' signal commercially endorsed (e.g., iOS, Android), where 0 = tracking is unrestricted, 1 = tracking must be limited per commercial guidelines.", + "type": "integer" + }, + "ip": { + "description": "IPv4 address closest to device.", + "type": "string" + }, + "ipv6": { + "description": "IPv6 address closest to device.", + "type": "string" + }, + "devicetype": { + "description": "The general type of device. Refer to List 5.21.", + "type": "integer" + }, + "make": { + "description": "Device make (e.g., 'Apple').", + "type": "string" + }, + "model": { + "description": "Device model (e.g., 'iPhone')", + "type": "string" + }, + "os": { + "description": "Device operating system (e.g., 'iOS').", + "type": "string" + }, + "osv": { + "description": "Device operating system version (e.g., '3.1.2').", + "type": "string" + }, + "hwv": { + "description": "Hardware version of the device (e.g., '5S' for iPhone 5S).", + "type": "string" + }, + "h": { + "description": "Physical height of the screen in pixels.", + "type": "integer" + }, + "w": { + "description": "Physical width of the screen in pixels.", + "type": "integer" + }, + "ppi": { + "description": "Screen size as pixels per linear inch.", + "type": "integer" + }, + "pxratio": { + "description": "The ratio of physical pixels to device independent pixels.", + "type": "number" + }, + "js": { + "description": "Support for JavaScript, where 0 = no, 1 = yes.", + "type": "integer" + }, + "geofetch": { + "description": "Indicates if the geolocation API will be available to JavaScript code running in the banner, where 0 = no, 1 = yes.", + "type": "integer" + }, + "language": { + "description": "Browser language using ISO-639-1-alpha-2.", + "type": "string" + }, + "carrier": { + "description": "Carrier or ISP (e.g., 'VERIZON') using exchange curated string names which should be published to bidders a priori.", + "type": "string" + }, + "mccmnc": { + "description": "Mobile carrier as the concatenated MCC-MNC code (e.g., '310-005' identifies Verizon Wireless CDMA in the USA). Refer to https://en.wikipedia.org/wiki/Mobile_country_code for further examples. Note that the dash between the MCC and MNC parts is required to remove parsing ambiguity.", + "type": "string" + }, + "connectiontype": { + "description": "Network connection type. Refer to List 5.22.", + "type": "integer" + }, + "ifa": { + "description": "ID sanctioned for advertiser use in the clear (i.e., not hashed).", + "type": "string" + }, + "didsha1": { + "description": "Hardware device ID (e.g., IMEI); hashed via SHA1.", + "type": "string" + }, + "didmd5": { + "description": "Hardware device ID (e.g., IMEI); hashed via MD5.", + "type": "string" + }, + "dpidsha1": { + "description": "Platform device ID (e.g., Android ID); hashed via SHA1.", + "type": "string" + }, + "dpidmd5": { + "description": "Platform device ID (e.g., Android ID); hashed via MD5.", + "type": "string" + }, + "macsha1": { + "description": "MAC address of the device; hashed via SHA1.", + "type": "string" + }, + "macmd5": { + "description": "MAC address of the device; hashed via MD5.", + "type": "string" + } + } + }, + "user": { + "type": "object", + "properties": { + "id": { + "description": "Exchange-specific ID for the user.", + "type": "string" + }, + "buyeruid": { + "description": "Buyer-specific ID for the user as mapped by the exchange for the buyer.", + "type": "string" + }, + "yob": { + "description": "Year of birth as a 4-digit integer.", + "type": "integer" + }, + "gender": { + "description": "Gender, where M=male, F=female, O=known to be other, omitted is unknown", + "type": "string" + } + } + }, + "ad_units": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": [ + "sizes", + "code" + ], + "oneOf": [ + { + "required": [ + "bids" + ] + }, + { + "required": [ + "config_id" + ] + } + ], + "properties": { + "code": { + "description": "Unique code of the ad unit on the page", + "type": "string" + }, + "sizes": { + "type": "array", + "items": { + "type": "object", + "properties": { "h": { - "description": "Physical height of the screen in pixels.", - "type": "integer" + "description": "Height of the ad unit", + "type": "integer" }, "w": { - "description": "Physical width of the screen in pixels.", - "type": "integer" - }, - "ppi": { - "description": "Screen size as pixels per linear inch.", - "type": "integer" - }, - "pxratio": { - "description": "The ratio of physical pixels to device independent pixels.", - "type": "number" - }, - "js": { - "description": "Support for JavaScript, where 0 = no, 1 = yes.", - "type": "integer" - }, - "geofetch": { - "description": "Indicates if the geolocation API will be available to JavaScript code running in the banner, where 0 = no, 1 = yes.", - "type": "integer" - }, - "language": { - "description": "Browser language using ISO-639-1-alpha-2.", - "type": "string" - }, - "carrier": { - "description": "Carrier or ISP (e.g., 'VERIZON') using exchange curated string names which should be published to bidders a priori.", - "type": "string" - }, - "mccmnc": { - "description": "Mobile carrier as the concatenated MCC-MNC code (e.g., '310-005' identifies Verizon Wireless CDMA in the USA). Refer to https://en.wikipedia.org/wiki/Mobile_country_code for further examples. Note that the dash between the MCC and MNC parts is required to remove parsing ambiguity.", - "type": "string" - }, - "connectiontype": { - "description": "Network connection type. Refer to List 5.22.", - "type": "integer" - }, - "ifa": { - "description": "ID sanctioned for advertiser use in the clear (i.e., not hashed).", - "type": "string" - }, - "didsha1": { - "description": "Hardware device ID (e.g., IMEI); hashed via SHA1.", - "type": "string" - }, - "didmd5": { - "description": "Hardware device ID (e.g., IMEI); hashed via MD5.", - "type": "string" - }, - "dpidsha1": { - "description": "Platform device ID (e.g., Android ID); hashed via SHA1.", - "type": "string" - }, - "dpidmd5": { - "description": "Platform device ID (e.g., Android ID); hashed via MD5.", - "type": "string" - }, - "macsha1": { - "description": "MAC address of the device; hashed via SHA1.", - "type": "string" - }, - "macmd5": { - "description": "MAC address of the device; hashed via MD5.", - "type": "string" + "description": "Width of the ad unit", + "type": "integer" } + } } - }, - "user": { + }, + "media_types": { + "type": "array", + "description": "Media types accepted by this ad unit", + "items": { + "type": "string", + "enum": [ + "banner", + "video" + ] + } + }, + "video": { "type": "object", + "description": "Video attributes of this ad Unit", "properties": { - "id": { - "description": "Exchange-specific ID for the user.", - "type": "string" - }, - "buyeruid": { - "description": "Buyer-specific ID for the user as mapped by the exchange for the buyer.", - "type": "string" - }, - "yob": { - "description": "Year of birth as a 4-digit integer.", - "type": "integer" - }, - "gender": { - "description": "Gender, where M=male, F=female, O=known to be other, omitted is unknown", - "type": "string" + "mimes": { + "type": "array", + "description": "Mime types as defined by ORTB - ex: video/mp4", + "items": { + "type": "string" } + }, + "minduration": { + "type": "integer", + "description": "Minimum video ad duration in seconds." + }, + "maxduration": { + "type": "integer", + "description": "Maximum video ad duration in seconds." + }, + "startdelay": { + "type": "integer", + "description": "Indicates the start delay in seconds for pre-roll, mid-roll, or post-roll ad placements." + }, + "skippable": { + "type": "integer", + "description": "Indicates if the player will allow the video to be skipped ( 0 = no, 1 = yes)." + }, + "playback_method": { + "type": "integer", + "description": "Playback method code as defined by ORTB." + }, + "protocols": { + "type": "integer", + "description": "protocols as specified in ORTB 2.5 spec: 5.8" + } } - }, - "ad_units": { + }, + "bids": { "type": "array", "minItems": 1, "items": { - "type": "object", - "required": [ - "sizes", - "code" - ], - "oneOf": [ - { - "required": [ - "bids" - ] - }, - { - "required": [ - "config_id" - ] - } - ], - "properties": { - "code": { - "description": "Unique code of the ad unit on the page", - "type": "string" - }, - "sizes": { - "type": "array", - "items": { - "type": "object", - "properties": { - "h": { - "description": "Height of the ad unit", - "type": "integer" - }, - "w": { - "description": "Width of the ad unit", - "type": "integer" - } - } - } - }, - "media_types": { - "type": "array", - "description": "Media types accepted by this ad unit", - "items": { - "type": "string", - "enum": [ - "banner", - "video" - ] - } - }, - "video": { - "type": "object", - "description": "Video attributes of this ad Unit", - "properties": { - "mimes": { - "type": "array", - "description": "Mime types as defined by ORTB - ex: video/mp4", - "items": { - "type": "string" - } - }, - "minduration": { - "type": "integer", - "description": "Minimum video ad duration in seconds." - }, - "maxduration": { - "type": "integer", - "description": "Maximum video ad duration in seconds." - }, - "startdelay": { - "type": "integer", - "description": "Indicates the start delay in seconds for pre-roll, mid-roll, or post-roll ad placements." - }, - "skippable": { - "type": "integer", - "description": "Indicates if the player will allow the video to be skipped ( 0 = no, 1 = yes)." - }, - "playback_method": { - "type": "integer", - "description": "Playback method code as defined by ORTB." - }, - "protocols": { - "type": "integer", - "description": "protocols as specified in ORTB 2.5 spec: 5.8" - } - } - }, - "bids": { - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "required": [ - "bidder", - "bid_id" - ], - "properties": { - "bid_id": { - "description": "Unique bid id for this bidder for this slot - for analytics", - "type": "string" - }, - "bidder": { - "description": "Unique code for an adapter to call", - "type": "string" - }, - "params": { - "description": "Optional params to send to the adapter", - "type": "object" - } - } - } - }, - "config_id": { - "description": "The config to load for this ad unit", - "type": "string" - }, - "slot_code": { - "description": "The slot code used by DFP", - "type": "string" - }, - "topframe": { - "description": "Whether this ad will render in the top IFRAME", - "type": "integer", - "minimum": 0, - "maximum": 1 - }, - "instl": { - "description": "1 = the ad is interstitial or full screen, 0 = not interstitial", - "type": "integer", - "minimum": 0, - "maximum": 1 - } + "type": "object", + "required": [ + "bidder", + "bid_id" + ], + "properties": { + "bid_id": { + "description": "Unique bid id for this bidder for this slot - for analytics", + "type": "string" + }, + "bidder": { + "description": "Unique code for an adapter to call", + "type": "string" + }, + "params": { + "description": "Optional params to send to the adapter", + "type": "object" } + } } + }, + "config_id": { + "description": "The config to load for this ad unit", + "type": "string" + }, + "slot_code": { + "description": "The slot code used by DFP", + "type": "string" + }, + "topframe": { + "description": "Whether this ad will render in the top IFRAME", + "type": "integer", + "minimum": 0, + "maximum": 1 + }, + "instl": { + "description": "1 = the ad is interstitial or full screen, 0 = not interstitial", + "type": "integer", + "minimum": 0, + "maximum": 1 + } } + } } -} \ No newline at end of file + } +} diff --git a/src/test/groovy/org/prebid/server/functional/model/pricefloors/Rule.groovy b/src/test/groovy/org/prebid/server/functional/model/pricefloors/Rule.groovy index 21415db1447..729514e7f5f 100644 --- a/src/test/groovy/org/prebid/server/functional/model/pricefloors/Rule.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/pricefloors/Rule.groovy @@ -1,7 +1,7 @@ package org.prebid.server.functional.model.pricefloors import com.fasterxml.jackson.annotation.JsonValue -import org.apache.commons.lang3.StringUtils +import org.apache.commons.lang3.Strings import org.prebid.server.functional.model.bidder.BidderName import java.lang.reflect.Modifier @@ -33,7 +33,7 @@ class Rule { stringBuilder.append(this[it.name]) .append(delimiter) } - StringUtils.removeEnd(stringBuilder.toString(), delimiter).toLowerCase() + Strings.CS.removeEnd(stringBuilder.toString(), delimiter).toLowerCase() } @JsonValue @@ -48,6 +48,6 @@ class Rule { result += classField[0] result += delimiter } - StringUtils.removeEnd(result, delimiter).toLowerCase() + Strings.CS.removeEnd(result, delimiter).toLowerCase() } } diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Audio.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Audio.groovy index 57d9bbd40ee..e262da95e35 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Audio.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Audio.groovy @@ -14,7 +14,7 @@ class Audio { List protocols Integer startdelay List rqddurs - Integer podid + String podid Integer podseq Integer sequence Integer slotinpod diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Content.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Content.groovy index 7b49458a5fc..5f6b638be1c 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Content.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Content.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.model.request.auction +import com.fasterxml.jackson.annotation.JsonProperty import groovy.transform.EqualsAndHashCode import groovy.transform.ToString import org.prebid.server.functional.util.PBSUtils @@ -15,6 +16,8 @@ class Content { String season String artist String genre + Integer gtax + List genres String album String isrc Producer producer @@ -29,6 +32,9 @@ class Content { String keywords List kwarray Integer livestream + Realtime realtime + @JsonProperty("firstbroadcast") + FirstBroadcast firstBroadcast Integer sourcerelationship Integer len String language diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Data.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Data.groovy index 894ba61e4cf..9731712864e 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Data.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Data.groovy @@ -10,6 +10,7 @@ class Data { String id String name + List cids List segment ExtData ext diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/FirstBroadcast.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/FirstBroadcast.groovy new file mode 100644 index 00000000000..03cfcebe68c --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/FirstBroadcast.groovy @@ -0,0 +1,15 @@ +package org.prebid.server.functional.model.request.auction + +import com.fasterxml.jackson.annotation.JsonValue + +enum FirstBroadcast { + + NOT_FIRST_BROADCAST(0), FIRST_BROADCAST(1) + + @JsonValue + final Integer value + + FirstBroadcast(Integer value) { + this.value = value + } +} diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Realtime.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Realtime.groovy new file mode 100644 index 00000000000..ab8cc908cd7 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Realtime.groovy @@ -0,0 +1,15 @@ +package org.prebid.server.functional.model.request.auction + +import com.fasterxml.jackson.annotation.JsonValue + +enum Realtime { + + REPLAY(0), REAL_TIME(1) + + @JsonValue + final Integer value + + Realtime(Integer value) { + this.value = value + } +} diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Video.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Video.groovy index 53e86c5ed28..e71191dc113 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Video.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Video.groovy @@ -19,7 +19,7 @@ class Video { Integer width @JsonProperty("h") Integer height - Integer podid + String podid Integer podseq List rqddurs VideoPlacementSubtypes placement diff --git a/src/test/groovy/org/prebid/server/functional/tests/MetricsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/MetricsSpec.groovy index ee3e808a56e..8a38ab04e60 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/MetricsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/MetricsSpec.groovy @@ -9,6 +9,7 @@ import org.prebid.server.functional.model.request.auction.Site import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.service.PrebidServerService +import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR import static org.prebid.server.functional.model.config.AccountMetricsVerbosityLevel.BASIC import static org.prebid.server.functional.model.config.AccountMetricsVerbosityLevel.DETAILED import static org.prebid.server.functional.model.config.AccountMetricsVerbosityLevel.NONE @@ -24,7 +25,7 @@ class MetricsSpec extends BaseSpec { flushMetrics(softPrebidService) } - def "PBS should not populate account metric when verbosity level is none"() { + def "PBS should only populate requests.gotbids account metric when verbosity level is none"() { given: "Default basic BidRequest with generic bidder" def bidRequest = BidRequest.defaultBidRequest @@ -39,7 +40,8 @@ class MetricsSpec extends BaseSpec { then: "account..* metric shouldn't be populated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert !metrics.find { it.key.startsWith("account.${accountId}") } + def filteredMetrics = metrics.findAll { it.key != "account.${accountId}.requests.gotbids" } + assert !filteredMetrics.find { it.key.startsWith("account.${accountId}") } } def "PBS should update account..requests metric when verbosity level is basic"() { @@ -94,9 +96,44 @@ class MetricsSpec extends BaseSpec { assert metrics["account.${accountId}.adapter.generic.request_time" as String] == 1 assert metrics["account.${accountId}.adapter.generic.requests.gotbids" as String] == 1 assert metrics["account.${accountId}.requests" as String] == 1 + assert metrics["account.${accountId}.requests.gotbids" as String] == 1 assert metrics["account.${accountId}.requests.type.openrtb2-web" as String] == 1 } + def "PBS should not populate bid-related account metrics for failed bidder response when verbosity level is detailed"() { + given: "Default basic BidRequest with generic bidder" + def bidRequest = BidRequest.defaultBidRequest + + and: "Default basic BidResponse with bid price" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest) + + and: "Set bidder response to internal server error" + bidder.setResponse(bidRequest.id, bidResponse, SC_INTERNAL_SERVER_ERROR) + + and: "Account in the DB" + def accountId = bidRequest.site.publisher.id + def accountMetricsConfig = new AccountConfig(metrics: new AccountMetricsConfig(verbosityLevel: DETAILED)) + def account = new Account(uuid: accountId, config: accountMetricsConfig) + accountDao.save(account) + + when: "PBS processes auction request" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "General request metrics should be populated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert metrics["account.${accountId}.requests" as String] == 1 + assert metrics["account.${accountId}.requests.type.openrtb2-web" as String] == 1 + + and: "Adapter request time should be populated" + assert metrics["account.${accountId}.adapter.generic.request_time" as String] == 1 + + and: "Bid-related metrics should not be populated due to bidder error" + assert !metrics["account.${accountId}.requests.gotbids" as String] + assert !metrics["account.${accountId}.adapter.generic.requests.gotbids" as String] + assert !metrics["account.${accountId}.adapter.generic.bids_received" as String] + assert !metrics["account.${accountId}.adapter.generic.prices" as String] + } + def "PBS should update hood metrics when bid request contains hood channel type and verbosity level is detailed"() { given: "Default basic BidRequest with generic bidder" def bidRequest = BidRequest.getDefaultBidRequest(DOOH) @@ -183,8 +220,8 @@ class MetricsSpec extends BaseSpec { where: bidRequest << [BidRequest.getDefaultBidRequest(APP).tap { - it.dooh = Dooh.defaultDooh - }, + it.dooh = Dooh.defaultDooh + }, BidRequest.getDefaultBidRequest(APP).tap { it.site = Site.defaultSite }, diff --git a/src/test/groovy/org/prebid/server/functional/tests/OrtbConverterSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/OrtbConverterSpec.groovy index 21bb80df135..61e9463ed41 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/OrtbConverterSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/OrtbConverterSpec.groovy @@ -4,15 +4,19 @@ import org.prebid.server.functional.model.db.StoredRequest import org.prebid.server.functional.model.request.auction.Audio import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Content +import org.prebid.server.functional.model.request.auction.Data import org.prebid.server.functional.model.request.auction.Device +import org.prebid.server.functional.model.request.auction.DistributionChannel import org.prebid.server.functional.model.request.auction.Dooh import org.prebid.server.functional.model.request.auction.DoohExt import org.prebid.server.functional.model.request.auction.Eid +import org.prebid.server.functional.model.request.auction.FirstBroadcast import org.prebid.server.functional.model.request.auction.Network import org.prebid.server.functional.model.request.auction.PrebidStoredRequest import org.prebid.server.functional.model.request.auction.Producer import org.prebid.server.functional.model.request.auction.Publisher import org.prebid.server.functional.model.request.auction.Qty +import org.prebid.server.functional.model.request.auction.Realtime import org.prebid.server.functional.model.request.auction.RefSettings import org.prebid.server.functional.model.request.auction.RefType import org.prebid.server.functional.model.request.auction.Refresh @@ -556,7 +560,7 @@ class OrtbConverterSpec extends BaseSpec { rqddurs = [PBSUtils.randomNumber] maxseq = PBSUtils.randomNumber poddur = PBSUtils.randomNumber - podid = PBSUtils.randomNumber + podid = PBSUtils.randomString podseq = PBSUtils.randomNumber mincpmpersec = PBSUtils.randomDecimal slotinpod = PBSUtils.randomNumber @@ -580,7 +584,7 @@ class OrtbConverterSpec extends BaseSpec { rqddurs = [PBSUtils.randomNumber] maxseq = PBSUtils.randomNumber poddur = PBSUtils.randomNumber - podid = PBSUtils.randomNumber + podid = PBSUtils.randomString podseq = PBSUtils.randomNumber mincpmpersec = PBSUtils.randomDecimal slotinpod = PBSUtils.randomNumber @@ -604,7 +608,7 @@ class OrtbConverterSpec extends BaseSpec { rqddurs = [PBSUtils.randomNumber] maxseq = PBSUtils.randomNumber poddur = PBSUtils.randomNumber - podid = PBSUtils.randomNumber + podid = PBSUtils.randomString podseq = PBSUtils.randomNumber mincpmpersec = PBSUtils.randomDecimal slotinpod = PBSUtils.randomNumber @@ -626,7 +630,7 @@ class OrtbConverterSpec extends BaseSpec { rqddurs = [PBSUtils.randomNumber] maxseq = PBSUtils.randomNumber poddur = PBSUtils.randomNumber - podid = PBSUtils.randomNumber + podid = PBSUtils.randomString podseq = PBSUtils.randomNumber mincpmpersec = BigDecimal.valueOf(1) slotinpod = PBSUtils.randomNumber @@ -671,6 +675,76 @@ class OrtbConverterSpec extends BaseSpec { assert bidderRequest.imp[0].ssai == ssaiRandomNumber } + def "PBS should preserve content metadata for #distributionChannel with ORTB 2.5"() { + given: "Content with genre taxonomy, broadcast flags, and extended content identifiers" + def content = Content.defaultContent.tap { + it.gtax = PBSUtils.getRandomNumber() + it.genres = [PBSUtils.randomString, PBSUtils.randomString] + it.realtime = PBSUtils.getRandomEnum(Realtime) + it.firstBroadcast = PBSUtils.getRandomEnum(FirstBroadcast) + it.data = [new Data(id: PBSUtils.randomString, cids: [PBSUtils.randomString, PBSUtils.randomString])] + } + def bidRequest = BidRequest.getDefaultBidRequest(distributionChannel).tap { + it[distributionChannel.value].content = content + } + + when: "Sending auction request to PBS" + def bidResponse = prebidServerServiceWithElderOrtb.sendAuctionRequest(bidRequest) + + then: "PBS responds without errors or warnings" + assert !bidResponse.ext.errors + assert !bidResponse.ext.warnings + + and: "PBS forwards the content metadata to the bidder unchanged" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + def actualContent = (bidderRequest[distributionChannel.value].content as Content) + verifyAll(actualContent) { + it.gtax == content.gtax + it.genres == content.genres + it.realtime == content.realtime + it.firstBroadcast == content.firstBroadcast + it.data == content.data + } + + where: + distributionChannel << DistributionChannel.values() + } + + def "PBS should preserve content metadata for #distributionChannel with ORTB 2.6"() { + given: "Content with genre taxonomy, broadcast flags, and extended content identifiers" + def content = Content.defaultContent.tap { + it.gtax = PBSUtils.getRandomNumber() + it.genres = [PBSUtils.randomString, PBSUtils.randomString] + it.realtime = PBSUtils.getRandomEnum(Realtime) + it.firstBroadcast = PBSUtils.getRandomEnum(FirstBroadcast) + it.data = [new Data(id: PBSUtils.randomString, cids: [PBSUtils.randomString, PBSUtils.randomString])] + } + def bidRequest = BidRequest.getDefaultBidRequest(distributionChannel).tap { + it[distributionChannel.value].content = content + } + + when: "Sending auction request to PBS" + def bidResponse = prebidServerServiceWithNewOrtb.sendAuctionRequest(bidRequest) + + then: "PBS responds without errors or warnings" + assert !bidResponse.ext.errors + assert !bidResponse.ext.warnings + + and: "PBS forwards the content metadata to the bidder unchanged" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + def actualContent = (bidderRequest[distributionChannel.value].content as Content) + verifyAll(actualContent) { + it.gtax == content.gtax + it.genres == content.genres + it.realtime == content.realtime + it.firstBroadcast == content.firstBroadcast + it.data == content.data + } + + where: + distributionChannel << DistributionChannel.values() + } + def "PBS shouldn't remove site.content.{channel, network} when bidder doesn't support ortb 2.6"() { given: "Default bid request with site.content.{network, channel}" def defaultChannel = Channel.defaultChannel 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 8619e9cf916..445a2d7e82f 100644 --- a/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy +++ b/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy @@ -51,7 +51,7 @@ class PBSUtils implements ObjectMapperWrapper { } static String getRandomSpecialChars(int stringLength = 20) { - RandomStringUtils.random(stringLength, "!@#\$%^&*()-_=+[]{}|;:'\",.<>/?") + RandomStringUtils.insecure().next(stringLength, "!@#\$%^&*()-_=+[]{}|;:'\",.<>/?") } static String getRandomStringWithSpecials(int stringLength = 20) { diff --git a/src/test/java/org/prebid/server/analytics/reporter/agma/AgmaAnalyticsReporterTest.java b/src/test/java/org/prebid/server/analytics/reporter/agma/AgmaAnalyticsReporterTest.java index e7ce7126031..5869bdb011f 100644 --- a/src/test/java/org/prebid/server/analytics/reporter/agma/AgmaAnalyticsReporterTest.java +++ b/src/test/java/org/prebid/server/analytics/reporter/agma/AgmaAnalyticsReporterTest.java @@ -460,7 +460,7 @@ public void processEventShouldSendWhenAccountsHasConfiguredAppsOrSites() { .build(); // when - final Future result = target.processEvent(auctionEvent); + target.processEvent(auctionEvent); // then final AgmaEvent expectedEvent = AgmaEvent.builder() @@ -518,7 +518,7 @@ public void processEventShouldSendWhenAccountsHasConfiguredAppsOrSitesOnly() { .build(); // when - final Future result = target.processEvent(auctionEvent); + target.processEvent(auctionEvent); // then final AgmaEvent expectedEvent = AgmaEvent.builder() diff --git a/src/test/java/org/prebid/server/auction/BasicCategoryMappingServiceTest.java b/src/test/java/org/prebid/server/auction/BasicCategoryMappingServiceTest.java index 9b68eb0560b..d47e3c39b0b 100644 --- a/src/test/java/org/prebid/server/auction/BasicCategoryMappingServiceTest.java +++ b/src/test/java/org/prebid/server/auction/BasicCategoryMappingServiceTest.java @@ -459,7 +459,7 @@ public void applyCategoryMappingShouldReturnFirstVideoCategoryIfPresent() { givenBidderResponse( "magnite", givenBidderBid( - givenBid("1", null, "10", singletonList("cat1"), "videoCategory"), + givenBid("1", "10", singletonList("cat1"), "videoCategory"), BidType.video, null, "videoCategory"))); @@ -474,7 +474,7 @@ public void applyCategoryMappingShouldReturnFirstVideoCategoryIfPresent() { // then assertThat(resultFuture.succeeded()).isTrue(); assertThat(resultFuture.result().getBiddersToBidsCategories()).isEqualTo( - Map.of(givenBid("1", null, "10", List.of("cat1"), "videoCategory"), "10.00_videoCategory_5s")); + Map.of(givenBid("1", "10", List.of("cat1"), "videoCategory"), "10.00_videoCategory_5s")); } @Test @@ -484,7 +484,7 @@ public void applyCategoryMappingShouldReturnEmptyCategoryIfNotWithCategory() { givenBidderResponse( "magnite", givenBidderBid( - givenBid("1", null, "10", singletonList("cat1"), "videoCategory"), + givenBid("1", "10", singletonList("cat1"), "videoCategory"), BidType.video, null, "videoCategory"))); @@ -499,7 +499,7 @@ public void applyCategoryMappingShouldReturnEmptyCategoryIfNotWithCategory() { // then assertThat(resultFuture.succeeded()).isTrue(); assertThat(resultFuture.result().getBiddersToBidsCategories()).isEqualTo( - Map.of(givenBid("1", null, "10", List.of("cat1"), "videoCategory"), "10.00_5s")); + Map.of(givenBid("1", "10", List.of("cat1"), "videoCategory"), "10.00_5s")); } @Test @@ -1220,8 +1220,8 @@ private static Bid givenBid(String bidId, String impId, String price, List cat, String videoCategory) { - return givenBid(bidId, impId, price, cat).toBuilder() + private static Bid givenBid(String bidId, String price, List cat, String videoCategory) { + return givenBid(bidId, null, price, cat).toBuilder() .ext(mapper.valueToTree( ExtBidPrebid.builder() .video(ExtBidPrebidVideo.of(null, videoCategory)) diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index 7d8d939600f..b8365ae867a 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -170,7 +170,6 @@ public class BidResponseCreatorTest extends VertxTest { private static final String IMP_ID = "impId1"; private static final String BID_ADM = "adm"; private static final String BID_NURL = "nurl"; - private static final String PREBID = "prebid"; @Mock private CoreCacheService coreCacheService; @@ -3882,7 +3881,7 @@ public void shouldPopulateExtPrebidSeatNonBidWhenReturnAllBidStatusFlagIsTrue() assertThat(bidResponse.getExt()) .extracting(ExtBidResponse::getSeatnonbid) - .asList() + .asInstanceOf(InstanceOfAssertFactories.LIST) .containsExactly(expectedSeatNonBid); } diff --git a/src/test/java/org/prebid/server/auction/CpmRangeTest.java b/src/test/java/org/prebid/server/auction/CpmRangeTest.java index c44ae1edd14..247a5a6ca06 100644 --- a/src/test/java/org/prebid/server/auction/CpmRangeTest.java +++ b/src/test/java/org/prebid/server/auction/CpmRangeTest.java @@ -219,17 +219,23 @@ public void fromCpmShouldReturnCpmGivenDenseGranularityAndThirdRange() { @Test public void fromCpmShouldReturnResultWithDefaultPrecisionTwoIfRangePrecisionInNull() { - assertThat(CpmRange.fromCpm(BigDecimal.valueOf(2.3333), createFromExtPriceGranularity( - ExtPriceGranularity.of(null, singletonList(ExtGranularityRange.of(BigDecimal.valueOf(3), - BigDecimal.valueOf(0.01))))), givenAccount())) + assertThat(CpmRange.fromCpm( + BigDecimal.valueOf(2.3333), + createFromExtPriceGranularity(ExtPriceGranularity.of( + null, + singletonList(ExtGranularityRange.of(BigDecimal.valueOf(3), BigDecimal.valueOf(0.01))))), + givenAccount())) .isEqualTo("2.33"); } @Test public void fromCpmShouldReturnResultWithPrecisionZero() { - assertThat(CpmRange.fromCpm(BigDecimal.valueOf(2.3333), createFromExtPriceGranularity( - ExtPriceGranularity.of(0, singletonList(ExtGranularityRange.of(BigDecimal.valueOf(3), - BigDecimal.valueOf(0.01))))), givenAccount())) + assertThat(CpmRange.fromCpm( + BigDecimal.valueOf(2.3333), + createFromExtPriceGranularity(ExtPriceGranularity.of( + 0, + singletonList(ExtGranularityRange.of(BigDecimal.valueOf(3), BigDecimal.valueOf(0.01))))), + givenAccount())) .isEqualTo("2"); } diff --git a/src/test/java/org/prebid/server/auction/DsaEnforcerTest.java b/src/test/java/org/prebid/server/auction/DsaEnforcerTest.java index 916cb934482..10505dde290 100644 --- a/src/test/java/org/prebid/server/auction/DsaEnforcerTest.java +++ b/src/test/java/org/prebid/server/auction/DsaEnforcerTest.java @@ -11,10 +11,10 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.VertxTest; import org.prebid.server.auction.model.AuctionParticipation; +import org.prebid.server.auction.model.BidRejection; import org.prebid.server.auction.model.BidRejectionReason; import org.prebid.server.auction.model.BidRejectionTracker; import org.prebid.server.auction.model.BidderResponse; -import org.prebid.server.auction.model.BidRejection; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderError; import org.prebid.server.bidder.model.BidderSeatBid; @@ -81,8 +81,8 @@ public void enforceShouldRejectBidAndAddWarningWhenDsaIsNotRequiredAndDsaRespons final ExtRegs extRegs = givenExtRegs(DsaRequired.NOT_REQUIRED, DsaPublisherRender.NOT_RENDER); final BidRequest givenRequest = BidRequest.builder().regs(Regs.builder().ext(extRegs).build()).build(); final ObjectNode dsaNode = mapper.createObjectNode() - .put("behalf", RandomStringUtils.randomAlphabetic(101)) - .put("paid", RandomStringUtils.randomAlphabetic(100)) + .put("behalf", RandomStringUtils.insecure().nextAlphabetic(101)) + .put("paid", RandomStringUtils.insecure().nextAlphabetic(100)) .put("adrender", DsaAdvertiserRender.NOT_RENDER.getValue()); final ObjectNode ext = mapper.createObjectNode().set("dsa", dsaNode); final BidderBid bid = BidderBid.of( @@ -114,8 +114,8 @@ public void enforceShouldRejectBidAndAddWarningWhenDsaIsNotRequiredAndDsaRespons final ExtRegs extRegs = givenExtRegs(DsaRequired.NOT_REQUIRED, DsaPublisherRender.NOT_RENDER); final BidRequest givenRequest = BidRequest.builder().regs(Regs.builder().ext(extRegs).build()).build(); final ObjectNode dsaNode = mapper.createObjectNode() - .put("behalf", RandomStringUtils.randomAlphabetic(100)) - .put("paid", RandomStringUtils.randomAlphabetic(101)) + .put("behalf", RandomStringUtils.insecure().nextAlphabetic(100)) + .put("paid", RandomStringUtils.insecure().nextAlphabetic(101)) .put("adrender", DsaAdvertiserRender.NOT_RENDER.getValue()); final ObjectNode ext = mapper.createObjectNode().set("dsa", dsaNode); final BidderBid bid = BidderBid.of( @@ -344,8 +344,8 @@ public void enforceShouldRejectBidAndAddWarningWhenDsaIsRequiredAndDsaResponseHa final BidRequest givenRequest = BidRequest.builder().regs(Regs.builder().ext(extRegs).build()).build(); final ObjectNode dsaNode = mapper.createObjectNode() - .put("behalf", RandomStringUtils.randomAlphabetic(100)) - .put("paid", RandomStringUtils.randomAlphabetic(101)) + .put("behalf", RandomStringUtils.insecure().nextAlphabetic(100)) + .put("paid", RandomStringUtils.insecure().nextAlphabetic(101)) .put("adrender", DsaAdvertiserRender.NOT_RENDER.getValue()); final ObjectNode ext = mapper.createObjectNode().set("dsa", dsaNode); final BidderBid bid = BidderBid.of( @@ -378,8 +378,8 @@ public void enforceShouldRejectBidAndAddWarningWhenDsaIsRequiredAndDsaResponseHa final BidRequest givenRequest = BidRequest.builder().regs(Regs.builder().ext(extRegs).build()).build(); final ObjectNode dsaNode = mapper.createObjectNode() - .put("behalf", RandomStringUtils.randomAlphabetic(101)) - .put("paid", RandomStringUtils.randomAlphabetic(100)) + .put("behalf", RandomStringUtils.insecure().nextAlphabetic(101)) + .put("paid", RandomStringUtils.insecure().nextAlphabetic(100)) .put("adrender", DsaAdvertiserRender.NOT_RENDER.getValue()); final ObjectNode ext = mapper.createObjectNode().set("dsa", dsaNode); final BidderBid bid = BidderBid.of( diff --git a/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java b/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java index d021aeb1fd0..b37d908f286 100644 --- a/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java +++ b/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java @@ -2089,7 +2089,8 @@ public void shouldAddMultiBidInfoAboutRequestedBidderIgnoringCaseIfDataShouldNot final ExtRequest extRequest = captureBidRequest().getExt(); assertThat(extRequest) .extracting(ExtRequest::getPrebid) - .extracting(ExtRequestPrebid::getMultibid).asList() + .extracting(ExtRequestPrebid::getMultibid) + .asInstanceOf(InstanceOfAssertFactories.LIST) .containsExactly(ExtRequestPrebidMultiBid.of("someBidder", null, 3, "prefix")); } @@ -2109,7 +2110,8 @@ public void shouldAddMultibidInfoOnlyAboutRequestedBidder() { final ExtRequest extRequest = captureBidRequest().getExt(); assertThat(extRequest) .extracting(ExtRequest::getPrebid) - .extracting(ExtRequestPrebid::getMultibid).asList() + .extracting(ExtRequestPrebid::getMultibid) + .asInstanceOf(InstanceOfAssertFactories.LIST) .containsExactly(ExtRequestPrebidMultiBid.of("someBidder", null, 3, null)); } @@ -3077,6 +3079,22 @@ public void shouldIncrementCommonMetrics() { eq("someBidder"), any(), eq(10000L), eq(false), eq("banner")); } + @Test + public void shouldIncrementAccountRequestGotbidsMetricAtMostOncePerRequest() { + // given + given(httpBidderRequester.requestBids(any(), any(), any(), any(), any(), any(), anyBoolean())) + .willReturn(Future.succeededFuture(givenSeatBid(singletonList( + givenBidderBid(Bid.builder().impid("impId").price(TEN).build()))))); + + final BidRequest bidRequest = givenBidRequest(givenSingleImp(Map.of("firstBidder", 1, "secondBidder", 2))); + + // when + target.holdAuction(givenRequestContext(bidRequest)); + + // then + verify(metrics, times(1)).updateAccountRequestGotbidsMetric("accountId"); + } + @Test public void shouldValidateBidsWithExtRequestPrebidAlternateBidderCodes() { // given @@ -4614,12 +4632,6 @@ private BidRequest captureBidRequest() { return bidRequestCaptor.getValue().getBidRequest(); } - private List captureAuctionParticipations() { - final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(AuctionContext.class); - verify(bidResponseCreator).create(contextArgumentCaptor.capture(), any(), any()); - return contextArgumentCaptor.getValue().getAuctionParticipations(); - } - private static BidRequest givenBidRequest(List imp, UnaryOperator bidRequestBuilderCustomizer) { diff --git a/src/test/java/org/prebid/server/auction/OrtbTypesResolverTest.java b/src/test/java/org/prebid/server/auction/OrtbTypesResolverTest.java index 7c0797ffacd..0ba078cb529 100644 --- a/src/test/java/org/prebid/server/auction/OrtbTypesResolverTest.java +++ b/src/test/java/org/prebid/server/auction/OrtbTypesResolverTest.java @@ -471,12 +471,12 @@ public void normalizeBidRequestShouldBeMergedWithFpdContextToOrtbSite() { .put("fpdData", "data_value"); final ObjectNode expectedOrtb = mapper.createObjectNode() - .put("id", "ortb_id") - .put("name", "name1") - .put("domain", "ortb_domain1") - .put("page", "ortb_page1") - .put("ref", "ortb_ref1") - .put("keywords", "ortb_keyword1,ortb_keyword2"); + .put("id", "ortb_id") + .put("name", "name1") + .put("domain", "ortb_domain1") + .put("page", "ortb_page1") + .put("ref", "ortb_ref1") + .put("keywords", "ortb_keyword1,ortb_keyword2"); expectedOrtb.set("ext", obj("data", expectedOrtbExtData)); assertThat(ortb2.path("site")).isEqualTo(expectedOrtb); diff --git a/src/test/java/org/prebid/server/auction/VideoResponseFactoryTest.java b/src/test/java/org/prebid/server/auction/VideoResponseFactoryTest.java index a5e9f2bb14f..33dcb92fbc6 100644 --- a/src/test/java/org/prebid/server/auction/VideoResponseFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/VideoResponseFactoryTest.java @@ -71,7 +71,7 @@ public void shouldUpdateCachedDebugLogAndResponseWhenZeroAdPods() { assertThat(result.getAdPods()).hasSize(1) .extracting(ExtAdPod::getTargeting) .hasSize(1) - .extracting(extResponseVideoTargetings -> extResponseVideoTargetings.getFirst()) + .extracting(List::getFirst) .extracting(ExtResponseVideoTargeting::getHbCacheID) .containsOnly("generatedId"); assertThat(cachedDebugLog.hasBids()).isFalse(); diff --git a/src/test/java/org/prebid/server/auction/privacy/enforcement/PrivacyEnforcementServiceTest.java b/src/test/java/org/prebid/server/auction/privacy/enforcement/PrivacyEnforcementServiceTest.java index 187985e4149..9f77e6e9795 100644 --- a/src/test/java/org/prebid/server/auction/privacy/enforcement/PrivacyEnforcementServiceTest.java +++ b/src/test/java/org/prebid/server/auction/privacy/enforcement/PrivacyEnforcementServiceTest.java @@ -4,6 +4,8 @@ import com.iab.openrtb.request.Device; import com.iab.openrtb.request.User; import io.vertx.core.Future; +import org.apache.commons.lang3.tuple.Pair; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -11,7 +13,6 @@ import org.prebid.server.auction.aliases.BidderAliases; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.BidderPrivacyResult; -import org.apache.commons.lang3.tuple.Pair; import java.util.List; import java.util.Map; @@ -68,7 +69,7 @@ public void maskShouldPassBidderPrivacyThroughAllEnforcements() { assertThat(result) .isSucceeded() .unwrap() - .asList() + .asInstanceOf(InstanceOfAssertFactories.LIST) .containsExactlyInAnyOrder(expectedResult); } } diff --git a/src/test/java/org/prebid/server/bidadjustments/BidAdjustmentRulesValidatorTest.java b/src/test/java/org/prebid/server/bidadjustments/BidAdjustmentRulesValidatorTest.java index a9634e568fd..102d1047aed 100644 --- a/src/test/java/org/prebid/server/bidadjustments/BidAdjustmentRulesValidatorTest.java +++ b/src/test/java/org/prebid/server/bidadjustments/BidAdjustmentRulesValidatorTest.java @@ -249,18 +249,18 @@ public void validateShouldDoNothingWhenAllRulesAreValid() throws ValidationExcep Map.of("dealId", givenRules)); final BidAdjustments givenBidAdjustments = BidAdjustments.of(Map.of( - "audio", givenRulesMap, - "native", givenRulesMap, - "video-instream", givenRulesMap, - "video-outstream", givenRulesMap, - "banner", givenRulesMap, - "video", givenRulesMap, - "unknown", givenRulesMap, - "*", Map.of( - "*", Map.of("*", givenRules), - "bidderName", Map.of( - "*", givenRules, - "dealId", givenRules)))); + "audio", givenRulesMap, + "native", givenRulesMap, + "video-instream", givenRulesMap, + "video-outstream", givenRulesMap, + "banner", givenRulesMap, + "video", givenRulesMap, + "unknown", givenRulesMap, + "*", Map.of( + "*", Map.of("*", givenRules), + "bidderName", Map.of( + "*", givenRules, + "dealId", givenRules)))); //when & then BidAdjustmentRulesValidator.validate(givenBidAdjustments); diff --git a/src/test/java/org/prebid/server/bidadjustments/BidAdjustmentsProcessorTest.java b/src/test/java/org/prebid/server/bidadjustments/BidAdjustmentsProcessorTest.java index 375ece90181..7034b1a4d05 100644 --- a/src/test/java/org/prebid/server/bidadjustments/BidAdjustmentsProcessorTest.java +++ b/src/test/java/org/prebid/server/bidadjustments/BidAdjustmentsProcessorTest.java @@ -16,6 +16,7 @@ import org.prebid.server.auction.model.AuctionParticipation; import org.prebid.server.auction.model.BidderRequest; import org.prebid.server.auction.model.BidderResponse; +import org.prebid.server.bidadjustments.model.BidAdjustments; import org.prebid.server.bidadjustments.model.BidAdjustmentsRules; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderError; @@ -25,7 +26,6 @@ import org.prebid.server.exception.PreBidException; import org.prebid.server.proto.openrtb.ext.request.ExtRequest; import org.prebid.server.proto.openrtb.ext.request.ExtRequestBidAdjustmentFactors; -import org.prebid.server.bidadjustments.model.BidAdjustments; import org.prebid.server.proto.openrtb.ext.request.ExtRequestCurrency; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; import org.prebid.server.proto.openrtb.ext.request.ImpMediaType; diff --git a/src/test/java/org/prebid/server/bidder/adelement/AdelementBidderTest.java b/src/test/java/org/prebid/server/bidder/adelement/AdelementBidderTest.java index 61ee34a7221..c3a9a89c343 100644 --- a/src/test/java/org/prebid/server/bidder/adelement/AdelementBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adelement/AdelementBidderTest.java @@ -71,7 +71,7 @@ public void makeHttpRequestsShouldCreateCorrectURL() { @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given - final BidderCall httpCall = givenHttpCall(null, "invalid"); + final BidderCall httpCall = givenHttpCall("invalid"); // when final Result> result = adelementBidder.makeBids(httpCall, null); @@ -106,9 +106,9 @@ private static Imp givenImp(Function impCustomiz .build(); } - private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), + HttpRequest.builder().payload(null).build(), HttpResponse.of(200, null, body), null); } diff --git a/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java b/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java index b2f1f9e4342..9956ecbff97 100644 --- a/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java @@ -18,13 +18,14 @@ import com.iab.openrtb.response.Bid; import io.vertx.core.MultiMap; import org.apache.commons.lang3.BooleanUtils; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.prebid.server.VertxTest; -import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusNativeRequest; -import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusRequestAdUnit; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusMetaData; +import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusNativeRequest; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusRequest; +import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusRequestAdUnit; import org.prebid.server.bidder.adnuntius.model.response.AdnuntiusAd; import org.prebid.server.bidder.adnuntius.model.response.AdnuntiusAdUnit; import org.prebid.server.bidder.adnuntius.model.response.AdnuntiusAdvertiser; @@ -1237,7 +1238,8 @@ public void makeBidsShouldReturnTwoBidFromDealsAndAdsWhenAdsAndDealsIsSpecified( assertThat(bid).extracting(Bid::getCrid).isEqualTo("creativeId"); assertThat(bid).extracting(Bid::getMtype).isEqualTo(1); assertThat(bid).extracting(Bid::getPrice).isEqualTo(BigDecimal.valueOf(1000)); - assertThat(bid).extracting(Bid::getAdomain).asList() + assertThat(bid).extracting(Bid::getAdomain) + .asInstanceOf(InstanceOfAssertFactories.LIST) .containsExactlyInAnyOrder("domain1.com", "domain2.dt"); assertThat(bid).extracting(Bid::getExt).isNull(); }); @@ -1295,7 +1297,8 @@ public void makeBidsShouldReturnTwoBidFromDealsAndAdsWhenNativeAdsAndDealsIsSpec assertThat(bid).extracting(Bid::getCrid).isEqualTo("creativeId"); assertThat(bid).extracting(Bid::getPrice).isEqualTo(BigDecimal.valueOf(1000)); assertThat(bid).extracting(Bid::getMtype).isEqualTo(4); - assertThat(bid).extracting(Bid::getAdomain).asList() + assertThat(bid).extracting(Bid::getAdomain) + .asInstanceOf(InstanceOfAssertFactories.LIST) .containsExactlyInAnyOrder("domain1.com", "domain2.dt"); assertThat(bid).extracting(Bid::getExt).isNull(); }); @@ -1316,7 +1319,8 @@ public void makeBidsShouldReturnTwoBidFromDealsAndAdsWhenNativeAdsAndDealsIsSpec assertThat(bid).extracting(Bid::getCrid).isEqualTo("creativeId"); assertThat(bid).extracting(Bid::getPrice).isEqualTo(BigDecimal.valueOf(1000)); assertThat(bid).extracting(Bid::getMtype).isEqualTo(1); - assertThat(bid).extracting(Bid::getAdomain).asList() + assertThat(bid).extracting(Bid::getAdomain) + .asInstanceOf(InstanceOfAssertFactories.LIST) .containsExactlyInAnyOrder("domain1.com", "domain2.dt"); assertThat(bid).extracting(Bid::getExt).isNull(); }); @@ -1452,7 +1456,8 @@ public void makeBidsShouldReturnCorrectSeatBids() throws JsonProcessingException assertThat(bid).extracting(Bid::getDealid).isEqualTo("dealId"); assertThat(bid).extracting(Bid::getCrid).isEqualTo("creativeId"); assertThat(bid).extracting(Bid::getPrice).isEqualTo(BigDecimal.valueOf(1000)); - assertThat(bid).extracting(Bid::getAdomain).asList() + assertThat(bid).extracting(Bid::getAdomain) + .asInstanceOf(InstanceOfAssertFactories.LIST) .containsExactlyInAnyOrder("domain1.com", "domain2.dt"); }); assertThat(bidderBid).extracting(BidderBid::getType).isEqualTo(BidType.banner); diff --git a/src/test/java/org/prebid/server/bidder/adot/AdotBidderTest.java b/src/test/java/org/prebid/server/bidder/adot/AdotBidderTest.java index 9eab23e3784..586592b3fee 100644 --- a/src/test/java/org/prebid/server/bidder/adot/AdotBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adot/AdotBidderTest.java @@ -115,7 +115,7 @@ public void makeHttpRequestsShouldNotChangeUrlWhenExtImpNotBeParsed() { @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given - final BidderCall httpCall = givenHttpCall(null, "invalid"); + final BidderCall httpCall = givenHttpCall("invalid"); // when final Result> result = target.makeBids(httpCall, null); @@ -130,7 +130,7 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { @Test public void makeBidsShouldReturnEmptyListIfBidResponseIsEmpty() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(null)); + final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(null)); // when final Result> result = target.makeBids(httpCall, null); @@ -143,7 +143,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseIsEmpty() throws JsonProce @Test public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsEmpty() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(BidResponse.builder().build())); // when @@ -157,7 +157,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsEmpty() throws Js @Test public void makeBidsShouldReturnEmptyListIfBidExtAdotMediaTypeIsInvalid() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(givenBidResponse("invalid"))); // when @@ -171,7 +171,7 @@ public void makeBidsShouldReturnEmptyListIfBidExtAdotMediaTypeIsInvalid() throws @Test public void makeBidsShouldReturnVideoBidWhenBidExtAdotMediaTypeIsVideo() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(givenBidResponse("video"))); // when @@ -186,7 +186,7 @@ public void makeBidsShouldReturnVideoBidWhenBidExtAdotMediaTypeIsVideo() throws @Test public void makeBidsShouldReturnVideoBidWhenBidExtAdotMediaTypeIsBanner() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(givenBidResponse("banner"))); // when @@ -201,7 +201,7 @@ public void makeBidsShouldReturnVideoBidWhenBidExtAdotMediaTypeIsBanner() throws @Test public void makeBidsShouldReturnVideoBidWhenBidExtAdotMediaTypeIsNative() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(givenBidResponse("native"))); // when @@ -216,7 +216,7 @@ public void makeBidsShouldReturnVideoBidWhenBidExtAdotMediaTypeIsNative() throws @Test public void makeBidsShouldReturnBidWithResolvedMacros() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(givenBidResponse( bidBuilder -> bidBuilder .nurl("nurl:${AUCTION_PRICE}") @@ -284,9 +284,9 @@ private static Bid givenBid(String bidExtMediaType) { .build(); } - private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), + HttpRequest.builder().payload(null).build(), HttpResponse.of(200, null, body), null); } diff --git a/src/test/java/org/prebid/server/bidder/adswag/AdswagBidderTest.java b/src/test/java/org/prebid/server/bidder/adswag/AdswagBidderTest.java new file mode 100644 index 00000000000..9451efc6247 --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/adswag/AdswagBidderTest.java @@ -0,0 +1,555 @@ +package org.prebid.server.bidder.adswag; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.App; +import com.iab.openrtb.request.Audio; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Format; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.Publisher; +import com.iab.openrtb.request.Site; +import com.iab.openrtb.request.Video; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.junit.jupiter.api.Test; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.HttpResponse; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.adswag.ExtImpAdswag; +import org.prebid.server.proto.openrtb.ext.response.BidType; + +import java.math.BigDecimal; +import java.util.List; +import java.util.function.UnaryOperator; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static java.util.function.UnaryOperator.identity; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.tuple; + +public class AdswagBidderTest extends VertxTest { + + private static final String ENDPOINT_URL = "https://test.endpoint.com/prebid/bid"; + private static final String SERVE_URL = "https://ads.adswag.ai/v1/ad?sc=c2ln&sig=YWJj"; + private static final String VAST_ADM = """ + \ + Adswag\ + \ + """; + private static final String IFRAME_ADM = """ + """; + + private final AdswagBidder target = new AdswagBidder(ENDPOINT_URL, jacksonMapper); + + @Test + public void creationShouldFailOnInvalidEndpointUrl() { + assertThatIllegalArgumentException().isThrownBy(() -> new AdswagBidder("invalid_url", jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { + // given + final BidRequest bidRequest = givenBidRequest(givenImp( + imp -> imp.id("imp1").ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input); + assertThat(error.getMessage()).startsWith("Error parsing imp.ext for impression imp1"); + }); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeHttpRequestsShouldReturnErrorIfPublisherIdIsMissing() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp1").ext(givenImpExt(" ", "placement")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input); + assertThat(error.getMessage()).isEqualTo("missing publisherId for imp imp1"); + }); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeHttpRequestsShouldReturnErrorIfNeitherSiteNorAppIsPresent() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp1").ext(givenImpExt("pub-1", null)))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input); + assertThat(error.getMessage()).isEqualTo("request must contain either site or app"); + }); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeHttpRequestsShouldPromotePublisherIdAndRewriteImpExt() { + // given + final ObjectNode impExt = givenImpExt("pub-1", "plc-1"); + impExt.put("gpid", "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/1111/homepage#div-1"); + final BidRequest bidRequest = givenBidRequest( + request -> request.site(Site.builder() + .publisher(Publisher.builder().name("Example").build()) + .build()), + givenImp(imp -> imp.id("imp1").ext(impExt))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getSite) + .extracting(Site::getPublisher) + .extracting(Publisher::getId, Publisher::getName) + .containsExactly(tuple("pub-1", "Example")); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .allSatisfy(ext -> { + assertThat(ext.has("bidder")).isFalse(); + assertThat(ext.get("gpid").textValue()).isEqualTo("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/1111/homepage#div-1"); + assertThat(ext.get("adswag").get("placement_id").textValue()).isEqualTo("plc-1"); + }); + } + + @Test + public void makeHttpRequestsShouldRemoveImpExtWhenOnlyBidderParamsPresent() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.site(Site.builder().domain("example.nl").build()), + givenImp(imp -> imp.id("imp1").ext(givenImpExt("pub-1", null)))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .containsOnlyNulls(); + } + + @Test + public void makeHttpRequestsShouldPromotePublisherIdToApp() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.app(App.builder().bundle("com.example.app").build()), + givenImp(imp -> imp.id("imp1").ext(givenImpExt("pub-1", null)))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getApp) + .extracting(App::getPublisher) + .extracting(Publisher::getId) + .containsExactly("pub-1"); + } + + @Test + public void makeHttpRequestsShouldDropImpsWithInvalidExtAndKeepValidOnes() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.site(Site.builder().domain("example.nl").build()), + givenImp(imp -> imp.id("imp1").ext(givenImpExt("pub-1", null))), + givenImp(imp -> imp.id("imp2").ext(givenImpExt(null, "plc-2")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> assertThat(error.getMessage()).isEqualTo("missing publisherId for imp imp2")); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getId) + .containsExactly("imp1"); + } + + @Test + public void makeHttpRequestsShouldSplitImpsByPublisherId() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.site(Site.builder().domain("example.nl").build()), + givenImp(imp -> imp.id("imp-a").ext(givenImpExt("pub-a", null))), + givenImp(imp -> imp.id("imp-b").ext(givenImpExt("pub-b", null))), + givenImp(imp -> imp.id("imp-a-2").ext(givenImpExt("pub-a", null)))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(2); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(payload -> payload.getSite().getPublisher().getId()) + .containsExactly("pub-a", "pub-b"); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(payload -> payload.getImp().stream().map(Imp::getId).toList()) + .containsExactly(List.of("imp-a", "imp-a-2"), List.of("imp-b")); + } + + @Test + public void makeBidsShouldReturnEmptyResultForEmptyBody() { + // given + final BidderCall httpCall = BidderCall.succeededHttp( + HttpRequest.builder().build(), + HttpResponse.of(200, null, ""), + null); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnErrorWhenResponseBodyCouldNotBeParsed() { + // given + final BidderCall httpCall = BidderCall.succeededHttp( + HttpRequest.builder().build(), + HttpResponse.of(200, null, "invalid_json"), + null); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response); + assertThat(error.getMessage()).startsWith("Failed to decode: Unrecognized token 'invalid_json'"); + }); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldSynthesizeIframeMarkupForBannerServeUrlBid() throws JsonProcessingException { + // given + final Bid responseBid = givenServeUrlBid("imp1"); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.id("imp1").banner(givenBanner()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getType, BidderBid::getBidCurrency) + .containsExactly(tuple(BidType.banner, "EUR")); + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getAdm, Bid::getW, Bid::getH, Bid::getMtype) + .containsExactly(tuple(IFRAME_ADM, 300, 250, 1)); + } + + @Test + public void makeBidsShouldPassThroughAdmWhenMarkupIsPresent() throws JsonProcessingException { + // given + final String loaderAdm = ""; + final Bid responseBid = givenServeUrlBid("imp1").toBuilder().adm(loaderAdm).build(); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.id("imp1").banner(givenBanner()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getAdm) + .containsExactly(loaderAdm); + } + + @Test + public void makeBidsShouldReturnVideoBidForVastMarkup() throws JsonProcessingException { + // given + final Bid responseBid = givenVastBid("imp1"); + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp1").video(Video.builder().w(640).h(360).build()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getType) + .containsExactly(BidType.video); + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getAdm, Bid::getW, Bid::getH, Bid::getMtype) + .containsExactly(tuple(VAST_ADM, 640, 360, 2)); + } + + @Test + public void makeBidsShouldReturnAudioBidForVastMarkupOnAudioImp() throws JsonProcessingException { + // given + final Bid responseBid = givenVastBid("imp1"); + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp1") + .banner(givenBanner()) + .audio(Audio.builder().mimes(singletonList("audio/mpeg")).build()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getType) + .containsExactly(BidType.audio); + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getMtype) + .containsExactly(3); + } + + @Test + public void makeBidsShouldResolveServeUrlBidOnMultiFormatImpAsBanner() throws JsonProcessingException { + // given + final Bid responseBid = givenServeUrlBid("imp1"); + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp1").banner(givenBanner()).video(Video.builder().w(640).h(360).build()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getType) + .containsExactly(BidType.banner); + } + + @Test + public void makeBidsShouldSetNurlForVideoServeUrlBidWithoutAdm() throws JsonProcessingException { + // given + final Bid responseBid = givenServeUrlBid("imp1"); + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp1").video(Video.builder().w(640).h(360).build()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getNurl, Bid::getMtype) + .containsExactly(tuple(SERVE_URL, 2)); + } + + @Test + public void makeBidsShouldHonorMtypeWhenPresent() throws JsonProcessingException { + // given + final Bid responseBid = givenVastBid("imp1").toBuilder().mtype(2).build(); + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp1") + .audio(Audio.builder().mimes(singletonList("audio/mpeg")).build()) + .video(Video.builder().w(640).h(360).build()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getType) + .containsExactly(BidType.video); + } + + @Test + public void makeBidsShouldReturnErrorForUnsupportedMtype() throws JsonProcessingException { + // given + final Bid responseBid = givenVastBid("imp1").toBuilder().mtype(4).build(); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.id("imp1").banner(givenBanner()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response); + assertThat(error.getMessage()).isEqualTo("unsupported bid.mtype 4 for impression imp1"); + }); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnErrorForUnknownImp() throws JsonProcessingException { + // given + final Bid responseBid = givenServeUrlBid("unknown-imp"); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.id("imp1").banner(givenBanner()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response); + assertThat(error.getMessage()) + .isEqualTo("bid adswag-unknown-imp references unknown imp unknown-imp"); + }); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnErrorForBidWithoutAdmOrServeUrl() throws JsonProcessingException { + // given + final Bid responseBid = Bid.builder() + .id("adswag-imp1") + .impid("imp1") + .price(BigDecimal.valueOf(2.5)) + .build(); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.id("imp1").banner(givenBanner()))); + final BidderCall httpCall = givenHttpCall(bidRequest, singletonList(responseBid)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response); + assertThat(error.getMessage()) + .isEqualTo("bid adswag-imp1 has neither adm nor ext.adswag.serve_url"); + }); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldDefaultCurrencyToEur() throws JsonProcessingException { + // given + final BidResponse bidResponse = BidResponse.builder() + .seatbid(singletonList(SeatBid.builder().bid(singletonList(givenServeUrlBid("imp1"))).build())) + .build(); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.id("imp1").banner(givenBanner()))); + final BidderCall httpCall = BidderCall.succeededHttp( + HttpRequest.builder().payload(bidRequest).build(), + HttpResponse.of(200, null, mapper.writeValueAsString(bidResponse)), + null); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getBidCurrency) + .containsExactly("EUR"); + } + + private static BidRequest givenBidRequest(UnaryOperator bidRequestCustomizer, + Imp... imps) { + + return bidRequestCustomizer.apply(BidRequest.builder().imp(asList(imps))).build(); + } + + private static BidRequest givenBidRequest(Imp... imps) { + return givenBidRequest(identity(), imps); + } + + private static Imp givenImp(UnaryOperator impCustomizer) { + return impCustomizer.apply(Imp.builder()).build(); + } + + private static ObjectNode givenImpExt(String publisherId, String placementId) { + return mapper.valueToTree(ExtPrebid.of(null, ExtImpAdswag.of(publisherId, placementId))); + } + + private static Banner givenBanner() { + return Banner.builder().format(singletonList(Format.builder().w(300).h(250).build())).build(); + } + + private static Bid givenServeUrlBid(String impId) { + final ObjectNode bidExt = mapper.createObjectNode(); + bidExt.putObject("adswag").put("serve_url", SERVE_URL); + return Bid.builder() + .id("adswag-" + impId) + .impid(impId) + .price(BigDecimal.valueOf(2.5)) + .crid("cr-1") + .ext(bidExt) + .build(); + } + + private static Bid givenVastBid(String impId) { + return Bid.builder() + .id("adswag-" + impId) + .impid(impId) + .price(BigDecimal.valueOf(2.5)) + .crid("cr-1") + .adm(VAST_ADM) + .build(); + } + + private static BidResponse givenBidResponse(List bids) { + return BidResponse.builder() + .cur("EUR") + .seatbid(singletonList(SeatBid.builder().bid(bids).build())) + .build(); + } + + private static BidderCall givenHttpCall(BidRequest bidRequest, List bids) + throws JsonProcessingException { + return BidderCall.succeededHttp( + HttpRequest.builder().payload(bidRequest).build(), + HttpResponse.of(200, null, mapper.writeValueAsString(givenBidResponse(bids))), + null); + } +} diff --git a/src/test/java/org/prebid/server/bidder/afront/AfrontBidderTest.java b/src/test/java/org/prebid/server/bidder/afront/AfrontBidderTest.java index e4769655520..69724e16802 100644 --- a/src/test/java/org/prebid/server/bidder/afront/AfrontBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/afront/AfrontBidderTest.java @@ -219,9 +219,10 @@ private static BidRequest givenBidRequest(UnaryOperator... impCu } private static Imp givenImp(UnaryOperator impCustomizer) { - return impCustomizer.apply(Imp.builder() - .id("impId") - .ext(givenImpExt("accountId", "sourceId"))) + return impCustomizer.apply( + Imp.builder() + .id("impId") + .ext(givenImpExt("accountId", "sourceId"))) .build(); } diff --git a/src/test/java/org/prebid/server/bidder/bidscube/BidscubeBidderTest.java b/src/test/java/org/prebid/server/bidder/bidscube/BidscubeBidderTest.java index 05c4a08ba1d..334eba5be04 100644 --- a/src/test/java/org/prebid/server/bidder/bidscube/BidscubeBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/bidscube/BidscubeBidderTest.java @@ -108,7 +108,7 @@ public void makeHttpRequestsShouldReturnErrorsOfNotValidImps() { @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given - final BidderCall httpCall = givenHttpCall(null, "invalid"); + final BidderCall httpCall = givenHttpCall("invalid"); // when final Result> result = target.makeBids(httpCall, null); @@ -125,7 +125,7 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { @Test public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(null)); + final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(null)); // when final Result> result = target.makeBids(httpCall, null); @@ -138,7 +138,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProces @Test public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(BidResponse.builder().build())); // when @@ -257,9 +257,9 @@ private static Imp givenImp(Function impCustomiz .build(); } - private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), + HttpRequest.builder().payload(null).build(), HttpResponse.of(200, null, body), null); } diff --git a/src/test/java/org/prebid/server/bidder/bidwave/BidwaveBidderTest.java b/src/test/java/org/prebid/server/bidder/bidwave/BidwaveBidderTest.java new file mode 100644 index 00000000000..43b814120c0 --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/bidwave/BidwaveBidderTest.java @@ -0,0 +1,318 @@ +package org.prebid.server.bidder.bidwave; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Device; +import com.iab.openrtb.request.Format; +import com.iab.openrtb.request.Geo; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.Site; +import com.iab.openrtb.request.Video; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.HttpResponse; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.bidwave.ExtImpBidwave; + +import java.math.BigDecimal; +import java.util.List; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.BDDAssertions.tuple; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; +import static org.prebid.server.proto.openrtb.ext.response.BidType.video; + +@ExtendWith(MockitoExtension.class) +public class BidwaveBidderTest extends VertxTest { + + private static final String ENDPOINT_URL = "https://rtb.bidwave.net/rtb/v1/bid"; + private static final String PUBLISHER_ID = "11111111-1111-4111-8111-111111111111"; + private static final String OTHER_PUBLISHER_ID = "22222222-2222-4222-8222-222222222222"; + + @Mock + private CurrencyConversionService currencyConversionService; + + private BidwaveBidder target; + + @BeforeEach + public void setUp() { + target = new BidwaveBidder(ENDPOINT_URL, currencyConversionService, jacksonMapper); + } + + @Test + public void creationShouldFailOnInvalidEndpointUrl() { + assertThatIllegalArgumentException() + .isThrownBy(() -> new BidwaveBidder("invalid_url", currencyConversionService, jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldSetBidwaveExt() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp-1").ext(givenImpExt(PUBLISHER_ID)))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1); + final BidRequest payload = result.getValue().getFirst().getPayload(); + + assertThat(payload.getExt().getProperty("bidwave").get("pid").asText()).isEqualTo(PUBLISHER_ID); + } + + @Test + public void makeHttpRequestsShouldSetDefaultCurrency() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp-1").ext(givenImpExt(PUBLISHER_ID)))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1); + final BidRequest payload = result.getValue().getFirst().getPayload(); + + assertThat(payload.getCur()).containsExactly("USD"); + } + + @Test + public void makeHttpRequestsShouldGroupImpsByPublisherId() { + // given + final Imp firstImp = givenImp(imp -> imp.id("imp-1").ext(givenImpExt(PUBLISHER_ID))); + final Imp secondImp = givenImp(imp -> imp.id("imp-2").ext(givenImpExt(OTHER_PUBLISHER_ID))); + final Imp thirdImp = givenImp(imp -> imp.id("imp-3").ext(givenImpExt(PUBLISHER_ID))); + final BidRequest bidRequest = givenBidRequest(firstImp, secondImp, thirdImp); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(2); + assertThat(result.getValue().get(0).getPayload()) + .satisfies(payload -> { + assertThat(payload.getImp()).containsExactly(firstImp, thirdImp); + assertThat(payload.getExt().getProperty("bidwave").get("pid").asText()) + .isEqualTo(PUBLISHER_ID); + }); + assertThat(result.getValue().get(1).getPayload()) + .satisfies(payload -> { + assertThat(payload.getImp()).containsExactly(secondImp); + assertThat(payload.getExt().getProperty("bidwave").get("pid").asText()) + .isEqualTo(OTHER_PUBLISHER_ID); + }); + } + + @Test + public void makeHttpRequestsShouldNormalizeCurrency() { + // given + final Imp imp = givenImp(impBuilder -> impBuilder.id("imp-1").ext(givenImpExt(PUBLISHER_ID))); + final BidRequest bidRequest = givenBidRequest(imp) + .toBuilder() + .cur(List.of("EUR")) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1); + assertThat(result.getValue().getFirst().getPayload().getCur()).containsExactly("USD"); + } + + @Test + public void makeHttpRequestsShouldConvertBidFloorCurrency() { + // given + given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) + .willReturn(BigDecimal.TEN); + + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .id("imp-1") + .bidfloor(BigDecimal.ONE) + .bidfloorcur("EUR") + .ext(givenImpExt(PUBLISHER_ID)))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsExactly(tuple(BigDecimal.TEN, "USD")); + } + + @Test + public void makeHttpRequestsShouldReturnErrorWhenBidFloorCurrencyCannotBeConverted() { + // given + given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) + .willThrow(new PreBidException("missing conversion rate")); + + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .id("imp-1") + .bidfloor(BigDecimal.ONE) + .bidfloorcur("EUR") + .ext(givenImpExt(PUBLISHER_ID)))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).containsExactly(BidderError.badInput( + "expected currency USD for bid floor; unable to convert from EUR for imp `imp-1`")); + } + + @Test + public void makeBidsShouldReturnBannerAndVideoBids() throws JsonProcessingException { + // given + final Bid bannerBid = Bid.builder().impid("imp-1").mtype(1).build(); + final Bid videoBid = Bid.builder().impid("imp-2").mtype(2).build(); + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("imp-1").banner(givenBanner()).ext(givenImpExt(PUBLISHER_ID))), + givenImp(imp -> imp.id("imp-2").video(givenVideo()).ext(givenImpExt(PUBLISHER_ID)))); + final BidderCall httpCall = sampleHttpCall( + bidRequest, + mapper.writeValueAsString(givenBidResponse(bannerBid, videoBid))); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsExactly( + BidderBid.of(bannerBid, banner, "USD"), + BidderBid.of(videoBid, video, "USD")); + } + + @Test + public void makeBidsShouldReturnErrorWhenMtypeIsAbsent() throws JsonProcessingException { + // given + final Bid bid = Bid.builder().impid("imp-1").build(); + final BidderCall httpCall = sampleHttpCall( + givenBidRequest(), + mapper.writeValueAsString(givenBidResponse(bid))); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).containsExactly( + BidderError.badServerResponse( + "Bid must have non-zero MType for impression with ID: \"imp-1\"")); + } + + @Test + public void makeBidsShouldReturnErrorIfMtypeIsUnsupported() throws JsonProcessingException { + // given + final Bid bid = Bid.builder().impid("imp-1").mtype(3).build(); + final BidderCall httpCall = sampleHttpCall( + givenBidRequest(givenImp(imp -> imp.id("imp-1").banner(givenBanner()).ext(givenImpExt(PUBLISHER_ID)))), + mapper.writeValueAsString(givenBidResponse(bid))); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).containsExactly( + BidderError.badServerResponse("Unsupported MType 3 for impression with ID: \"imp-1\"")); + } + + @Test + public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { + // given + final BidderCall httpCall = sampleHttpCall(givenBidRequest(), "invalid response"); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).hasSize(1) + .allMatch(error -> error.getType() == BidderError.Type.bad_server_response + && error.getMessage().startsWith("Failed to decode: Unrecognized token")); + } + + private static BidRequest givenBidRequest(Imp... imps) { + return BidRequest.builder() + .id("request-id") + .site(Site.builder().domain("publisher.example.com").build()) + .device(Device.builder() + .ip("203.0.113.42") + .geo(Geo.builder().country("USA").region("CA").city("San Francisco").build()) + .build()) + .imp(List.of(imps)) + .build(); + } + + private static BidRequest givenBidRequest() { + return givenBidRequest(givenImp(imp -> imp.id("imp-1").banner(givenBanner()).ext(givenImpExt(PUBLISHER_ID)))); + } + + private static Imp givenImp(java.util.function.Function impCustomizer) { + return impCustomizer.apply(Imp.builder()).build(); + } + + private static Banner givenBanner() { + return Banner.builder() + .format(singletonList(Format.builder().w(300).h(250).build())) + .build(); + } + + private static Video givenVideo() { + return Video.builder() + .mimes(singletonList("video/mp4")) + .protocols(List.of(2, 3)) + .w(640) + .h(360) + .build(); + } + + private static com.fasterxml.jackson.databind.node.ObjectNode givenImpExt(String publisherId) { + return mapper.valueToTree(ExtPrebid.of(null, ExtImpBidwave.of(publisherId))); + } + + private static BidResponse givenBidResponse(Bid... bids) { + return BidResponse.builder() + .cur("USD") + .seatbid(singletonList(SeatBid.builder().bid(List.of(bids)).build())) + .build(); + } + + private static BidderCall sampleHttpCall(BidRequest bidRequest, String body) { + return BidderCall.succeededHttp( + HttpRequest.builder().payload(bidRequest).build(), + HttpResponse.of(200, null, body), + null); + } +} diff --git a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java index 01fb0c58930..3a682098c10 100644 --- a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java @@ -106,7 +106,7 @@ public void makeHttpRequestsShouldUpdateDisplayManagerVer() { // given final BidRequest bidRequest = givenBidRequest( request -> request.app(App.builder().ext(ExtApp.of( - ExtAppPrebid.of("source", "version"), null)) + ExtAppPrebid.of("source", "version"), null)) .build()), givenImp(ExtImpConnatix.of("placementId", null))); @@ -176,7 +176,7 @@ public void makeHttpRequestsShouldUpdateBanner() { final BidRequest bidRequest = givenBidRequest( UnaryOperator.identity(), givenImp(impBuilder -> impBuilder.banner(Banner.builder().format(List.of( - Format.builder().w(300).h(250).build(), + Format.builder().w(300).h(250).build(), Format.builder().w(1).h(1).build())).build()) .ext(mapper.valueToTree( ExtPrebid.of(null, ExtImpConnatix.of("placementId", null)))))); @@ -440,9 +440,10 @@ public void makeBidsShouldReturnVideoBidSuccessfully() throws JsonProcessingExce private static BidRequest givenBidRequest(UnaryOperator bidRequestCustomizer, Imp... imps) { - return bidRequestCustomizer.apply(BidRequest.builder() - .device(Device.builder().ip("deviceIp").build()) - .imp(asList(imps))) + return bidRequestCustomizer.apply( + BidRequest.builder() + .device(Device.builder().ip("deviceIp").build()) + .imp(asList(imps))) .build(); } @@ -465,14 +466,6 @@ private static BidderCall givenHttpCall(String body) { null); } - private static BidderCall givenHttpCall(BidRequest request, - String response) throws JsonProcessingException { - return BidderCall.succeededHttp( - HttpRequest.builder().payload(request).build(), - HttpResponse.of(200, null, response), - null); - } - private static String givenBidResponse(Bid... bid) throws JsonProcessingException { return mapper.writeValueAsString(BidResponse.builder() .cur("USD") diff --git a/src/test/java/org/prebid/server/bidder/connectad/ConnectAdBidderTest.java b/src/test/java/org/prebid/server/bidder/connectad/ConnectAdBidderTest.java index 3ac89edc67a..122f4ffad8e 100644 --- a/src/test/java/org/prebid/server/bidder/connectad/ConnectAdBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/connectad/ConnectAdBidderTest.java @@ -49,6 +49,7 @@ public void makeHttpRequestsShouldReturnErrorWhenImpExtCouldNotBeParsed() { final BidRequest bidRequest = BidRequest.builder() .imp(singletonList(Imp.builder() .id("123") + .banner(Banner.builder().w(300).h(250).build()) .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))) .build())) .build(); @@ -109,12 +110,15 @@ public void makeBidsShouldReturnEmptyListWhenBidResponseSeatBidIsNull() throws J @Test public void makeBidsShouldReturnBannerBid() throws JsonProcessingException { // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").banner(Banner.builder().build()).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder().imp(singletonList(Imp.builder().id("123").build())).build(), + bidRequest, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); // when - final Result> result = target.makeBids(httpCall, null); + final Result> result = target.makeBids(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); @@ -146,7 +150,7 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtHasNoSiteId() { impBuilder -> impBuilder .id("123") .ext(mapper.valueToTree(ExtPrebid.of(null, - ExtImpConnectAd.of("12", null, BigDecimal.ONE))))); + ExtImpConnectAd.of(12, null, BigDecimal.ONE))))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -164,7 +168,7 @@ public void impSecureShouldBeOneIfSitePageStartsFromHttps() { impBuilder -> impBuilder .id("123") .ext(mapper.valueToTree(ExtPrebid.of(null, - ExtImpConnectAd.of("12", "1", BigDecimal.ONE))))); + ExtImpConnectAd.of(12, 1, BigDecimal.ONE))))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -180,6 +184,32 @@ public void impSecureShouldBeOneIfSitePageStartsFromHttps() { .containsOnly(1); } + @Test + public void makeHttpRequestsShouldPropagateSiteIdAndNetworkId() { + // given + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder + .id("123") + .ext(mapper.valueToTree(ExtPrebid.of(null, + ExtImpConnectAd.of(12345, 67890, BigDecimal.ONE))))); + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .hasSize(1) + .first() + .satisfies(imp -> { + assertThat(imp.getTagid()).isEqualTo("67890"); + assertThat(imp.getExt().get("networkId").asInt()).isEqualTo(12345); + assertThat(imp.getExt().get("siteId").asInt()).isEqualTo(67890); + }); + } + private static BidRequest givenBidRequest( Function bidRequestCustomizer, Function impCustomizer) { @@ -202,7 +232,7 @@ private static Imp givenImp(Function impCustomiz .w(14) .h(15).build()) .ext(mapper.valueToTree(ExtPrebid.of(null, - ExtImpConnectAd.of("12", "12", BigDecimal.ONE))))) + ExtImpConnectAd.of(12, 12, BigDecimal.ONE))))) .build(); } diff --git a/src/test/java/org/prebid/server/bidder/cpmstar/CpmStarBidderTest.java b/src/test/java/org/prebid/server/bidder/cpmstar/CpmStarBidderTest.java index 80ee546bfe3..243d9bcd1bd 100644 --- a/src/test/java/org/prebid/server/bidder/cpmstar/CpmStarBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/cpmstar/CpmStarBidderTest.java @@ -89,7 +89,7 @@ public void makeHttpRequestsShouldSkipInvalidImpressionAndAddError() { } @Test - public void makeHttpRequestsShouldPreserveExistingExtFieldsWhenFlatteningBidder() throws JsonProcessingException { + public void makeHttpRequestsShouldPreserveExistingExtFieldsWhenFlatteningBidder() { // given: final ObjectNode ext = mapper.createObjectNode(); ext.set("bidder", mapper.valueToTree(ExtImpCpmStar.of(12, 123))); diff --git a/src/test/java/org/prebid/server/bidder/elementaltv/ElementalTVBidderTest.java b/src/test/java/org/prebid/server/bidder/elementaltv/ElementalTVBidderTest.java index 60a6523ad2a..b8d0375214c 100644 --- a/src/test/java/org/prebid/server/bidder/elementaltv/ElementalTVBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/elementaltv/ElementalTVBidderTest.java @@ -163,10 +163,11 @@ private static BidRequest givenBidRequest(Function impCustomizer) { - return impCustomizer.apply(Imp.builder() - .id("123") - .banner(Banner.builder().id("banner_id").build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpElementalTV.of("adUnit"))))) + return impCustomizer.apply( + Imp.builder() + .id("123") + .banner(Banner.builder().id("banner_id").build()) + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpElementalTV.of("adUnit"))))) .build(); } diff --git a/src/test/java/org/prebid/server/bidder/eskimi/EskimiBidderTest.java b/src/test/java/org/prebid/server/bidder/eskimi/EskimiBidderTest.java new file mode 100644 index 00000000000..7c006a2db3f --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/eskimi/EskimiBidderTest.java @@ -0,0 +1,646 @@ +package org.prebid.server.bidder.eskimi; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.IntNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.App; +import com.iab.openrtb.request.Audio; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.Native; +import com.iab.openrtb.request.Site; +import com.iab.openrtb.request.Video; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.HttpResponse; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.ExtApp; +import org.prebid.server.proto.openrtb.ext.request.ExtSite; +import org.prebid.server.proto.openrtb.ext.request.eskimi.ExtImpEskimi; +import org.prebid.server.proto.openrtb.ext.response.BidType; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.UnaryOperator; + +import static java.util.Collections.singletonList; +import static java.util.function.UnaryOperator.identity; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.tuple; + +@ExtendWith(MockitoExtension.class) +public class EskimiBidderTest extends VertxTest { + + private static final String ENDPOINT_URL = "https://test.endpoint.com"; + private EskimiBidder target; + + @BeforeEach + public void setUp() { + target = new EskimiBidder(ENDPOINT_URL, jacksonMapper); + } + + @Test + public void creationShouldFailOnInvalidEndpointUrl() { + assertThatIllegalArgumentException().isThrownBy(() -> new EskimiBidder("invalid_url", jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldReturnErrorWhenFirstImpExtIsInvalid() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()) + .extracting(BidderError::getMessage) + .hasSize(1) + .allSatisfy(error -> assertThat(error).startsWith("invalid imp.ext for imp 123")); + } + + @Test + public void makeHttpRequestsShouldReturnErrorWhenSiteAndAppAreMissing() { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())).toBuilder() + .site(null) + .app(null) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()) + .extracting(BidderError::getMessage) + .containsExactly("request must contain either site or app"); + } + + @Test + public void makeHttpRequestsShouldAddErrorsOnInvalidImpsAndProcessValid() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(identity()), + givenImp(imp -> imp.id("456").ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()).hasSize(1); + assertThat(result.getErrors()) + .extracting(BidderError::getMessage) + .hasSize(1) + .allSatisfy(error -> assertThat(error).startsWith("invalid imp.ext for imp 456")); + } + + @Test + public void makeHttpRequestsShouldModifyImpSettingBattrForBannerAndVideoWhenEmpty() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .banner(Banner.builder().build()) + .video(Video.builder().build()) + .ext(givenImpExt(givenExtImpBattr(List.of(1, 2)))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner, Imp::getVideo) + .containsExactly(tuple( + Banner.builder().battr(List.of(1, 2)).build(), + Video.builder().battr(List.of(1, 2)).build())); + } + + @Test + public void makeHttpRequestsShouldNotOverrideBattrWhenAlreadyPresentInBannerOrVideo() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .banner(Banner.builder().battr(List.of(1, 2)).build()) + .video(Video.builder().battr(List.of(3, 4)).build()) + .ext(givenImpExt(givenExtImpBattr(List.of(5, 6)))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner, Imp::getVideo) + .containsExactly(tuple( + Banner.builder().battr(List.of(1, 2)).build(), + Video.builder().battr(List.of(3, 4)).build())); + } + + @Test + public void makeHttpRequestsShouldSetSecureToOneWhenNull() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.secure(null)), + givenImp(imp -> imp.secure(0)), + givenImp(imp -> imp.secure(1))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getSecure) + .containsExactly(1, 0, 1); + } + + @Test + public void makeHttpRequestsShouldUseImpBidfloorAndCurWhenValid() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .bidfloor(BigDecimal.TEN) + .bidfloorcur("USD") + .ext(givenImpExt(givenExtImpBidFloor(BigDecimal.ONE, "EUR"))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsExactly(tuple(BigDecimal.TEN, "USD")); + } + + @Test + public void makeHttpRequestsShouldFallbackToExtBidfloorAndCurWhenImpInvalid() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .bidfloor(BigDecimal.ZERO) + .bidfloorcur(null) + .ext(givenImpExt(givenExtImpBidFloor(BigDecimal.ONE, "EUR"))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsExactly(tuple(BigDecimal.ONE, "EUR")); + } + + @Test + public void makeHttpRequestsShouldFallbackToExtBidfloorButKeepImpCurWhenExtCurIsBlank() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .bidfloor(null) + .bidfloorcur("USD") + .ext(givenImpExt(givenExtImpBidFloor(BigDecimal.ONE, null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsExactly(tuple(BigDecimal.ONE, "USD")); + } + + @Test + public void makeHttpRequestsShouldApplyRequestParamsFromFirstImpExtWhenMissingInRequest() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(givenImpExt( + givenExtImpBlocked(List.of("cat1"), List.of("adv1"), List.of("app1")))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getBcat, BidRequest::getBadv, BidRequest::getBapp) + .containsExactly(tuple(List.of("cat1"), List.of("adv1"), List.of("app1"))); + } + + @Test + public void makeHttpRequestsShouldNotOverrideRequestParamsWhenPresentInRequest() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(givenImpExt( + givenExtImpBlocked(List.of("ext_cat1"), List.of("ext_adv1"), List.of("ext_app1")))))) + .toBuilder() + .bcat(List.of("req_cat1")) + .badv(List.of("req_adv1")) + .bapp(List.of("req_app1")) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getBcat, BidRequest::getBadv, BidRequest::getBapp) + .containsExactly(tuple(List.of("req_cat1"), List.of("req_adv1"), List.of("req_app1"))); + } + + @Test + public void makeHttpRequestsShouldSetPlacementIdInSiteExt() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(givenImpExt(givenExtImpEskimi(1))))) + .toBuilder() + .site(Site.builder().build()) + .app(null) + .build(); + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getSite) + .extracting(Site::getExt) + .extracting(ext -> ext.getProperty("placementId")) + .containsExactly(IntNode.valueOf(1)); + } + + @Test + public void makeHttpRequestsShouldSetPlacementIdInAppExt() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(givenImpExt(givenExtImpEskimi(1))))) + .toBuilder() + .site(null) + .app(App.builder().build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getApp) + .extracting(App::getExt) + .extracting(ext -> ext.getProperty("placementId")) + .containsExactly(IntNode.valueOf(1)); + } + + @Test + public void makeHttpRequestsShouldPreserveOriginalSiteExtAndSetPlacementId() { + // given + final ExtSite givenExtSite = ExtSite.of(null, mapper.createObjectNode().put("ANY", "ANY")); + + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(givenImpExt(givenExtImpEskimi(1))))) + .toBuilder() + .site(Site.builder().ext(givenExtSite).build()) + .app(null) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + final ExtSite expectedExtSite = ExtSite.of(null, mapper.createObjectNode().put("ANY", "ANY")); + expectedExtSite.addProperty("placementId", IntNode.valueOf(1)); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getSite) + .extracting(Site::getExt) + .containsExactly(expectedExtSite); + } + + @Test + public void makeHttpRequestsShouldPreserveOriginalAppExtAndSetPlacementId() { + // given + final ExtApp givenExtApp = ExtApp.of(null, mapper.createObjectNode().put("ANY", "ANY")); + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(givenImpExt(givenExtImpEskimi(1))))) + .toBuilder() + .site(null) + .app(App.builder().ext(givenExtApp).build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + final ExtApp expectedExtApp = ExtApp.of(null, mapper.createObjectNode().put("ANY", "ANY")); + expectedExtApp.addProperty("placementId", IntNode.valueOf(1)); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getApp) + .extracting(App::getExt) + .containsExactly(expectedExtApp); + } + + @Test + public void makeBidsShouldReturnErrorWhenResponseBodyCouldNotBeParsed() { + // given + final BidderCall httpCall = givenHttpCall(givenBidRequest(givenImp(identity())), "invalid"); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()) + .singleElement() + .extracting(BidderError::getMessage) + .asString() + .startsWith("Failed to decode: Unrecognized token"); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnEmptyResultWhenResponseHasNoSeatBids() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidResponse bidResponse = BidResponse.builder() + .seatbid(Collections.emptyList()) + .build(); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnBannerBidWhenMtypeIsBanner() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123").mtype(1)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getType) + .isEqualTo(BidType.banner); + } + + @Test + public void makeBidsShouldReturnVideoBidWhenMtypeIsVideo() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123").mtype(2)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getType) + .isEqualTo(BidType.video); + } + + @Test + public void makeBidsShouldReturnErrorWhenMtypeIsUnsupported() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123").mtype(3)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()) + .singleElement() + .extracting(BidderError::getMessage) + .isEqualTo("unsupported bid.mtype 3 for impression 123 (banner and video only)"); + } + + @Test + public void makeBidsShouldResolveBannerBidTypeFromImpWhenMtypeIsMissing() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.banner(Banner.builder().build()).video(null))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123").mtype(null)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getType) + .isEqualTo(BidType.banner); + } + + @Test + public void makeBidsShouldResolveVideoBidTypeFromImpWhenMtypeIsMissing() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.banner(null).video(Video.builder().build()))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123").mtype(null)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getType) + .isEqualTo(BidType.video); + } + + @Test + public void makeBidsShouldReturnErrorWhenMtypeIsMissingAndImpHasMultipleFormats() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.banner(Banner.builder().build()).video(Video.builder().build()))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123").mtype(null)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()) + .singleElement() + .extracting(BidderError::getMessage) + .isEqualTo("bid for multi-format imp 123 requires bid.mtype to disambiguate"); + } + + @Test + public void makeBidsShouldReturnErrorWhenMtypeMissingAndImpHasNoSupportedFormats() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .banner(null) + .video(null) + .audio(Audio.builder().build()) + .xNative(Native.builder().build()))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123").mtype(null)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()) + .singleElement() + .extracting(BidderError::getMessage) + .isEqualTo("unsupported media type for impression 123 (banner and video only)"); + } + + @Test + public void makeBidsShouldReturnErrorWhenMtypeIsMissingAndImpIdNotFound() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("404").mtype(null)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()) + .singleElement() + .extracting(BidderError::getMessage) + .isEqualTo("unable to resolve media type for impression 404"); + } + + private static BidRequest givenBidRequest(Imp... imps) { + return BidRequest.builder() + .cur(List.of("USD")) + .site(Site.builder().build()) + .imp(Arrays.stream(imps).toList()) + .build(); + } + + private static Imp givenImp(UnaryOperator impCustomizer) { + return impCustomizer.apply(Imp.builder() + .id("123") + .banner(Banner.builder().w(1).h(1).build()) + .ext(givenImpExt(givenExtImpEskimi(1)))) + .build(); + } + + private static ObjectNode givenImpExt(ExtImpEskimi extImpEskimi) { + return mapper.valueToTree(ExtPrebid.of(null, extImpEskimi)); + } + + private static ExtImpEskimi givenExtImpEskimi(Integer placementId) { + return ExtImpEskimi.of(placementId, null, null, null, null, null, null); + } + + private static ExtImpEskimi givenExtImpBattr(List battr) { + return ExtImpEskimi.of(1, null, null, null, null, null, battr); + } + + private static ExtImpEskimi givenExtImpBidFloor(BigDecimal bidFloor, String bidFloorCur) { + return ExtImpEskimi.of(1, bidFloor, bidFloorCur, null, null, null, null); + } + + private static ExtImpEskimi givenExtImpBlocked(List bcat, List badv, List bapp) { + return ExtImpEskimi.of(1, null, null, bcat, badv, bapp, null); + } + + private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + return BidderCall.succeededHttp( + HttpRequest.builder().payload(bidRequest).build(), + HttpResponse.of(200, null, body), + null); + } + + @SafeVarargs + private BidResponse givenBidResponse(UnaryOperator... bidCustomizers) { + return BidResponse.builder() + .seatbid(singletonList(SeatBid.builder() + .bid(Arrays.stream(bidCustomizers) + .map(bidCustomizer -> bidCustomizer.apply(Bid.builder()).build()) + .toList()) + .build())) + .build(); + } +} diff --git a/src/test/java/org/prebid/server/bidder/flipp/FlippBidderTest.java b/src/test/java/org/prebid/server/bidder/flipp/FlippBidderTest.java index 527ea6662ec..df2072393a0 100644 --- a/src/test/java/org/prebid/server/bidder/flipp/FlippBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/flipp/FlippBidderTest.java @@ -567,7 +567,7 @@ public void makeHttpRequestsShouldGenerateKeyForUserRequestBodyWhenKeyIsPresentB .extracting(CampaignRequestBody::getUser) .extracting(CampaignRequestBodyUser::getKey) .isNotEmpty() - .isNotEqualTo("any-key"); + .doesNotContain("any-key"); } @Test @@ -595,7 +595,7 @@ public void makeHttpRequestsShouldGenerateKeyForUserRequestBodyWhenKeyIsPresentB .extracting(CampaignRequestBody::getUser) .extracting(CampaignRequestBodyUser::getKey) .isNotEmpty() - .isNotEqualTo("any-key"); + .doesNotContain("any-key"); } @Test @@ -625,7 +625,7 @@ public void makeHttpRequestsShouldGenerateKeyForUserRequestBodyWhenKeyIsPresentB .extracting(CampaignRequestBody::getUser) .extracting(CampaignRequestBodyUser::getKey) .isNotEmpty() - .isNotEqualTo("any-key"); + .doesNotContain("any-key"); } @Test @@ -652,7 +652,7 @@ public void makeHttpRequestsShouldGenerateKeyForUserRequestBodyWhenKeyIsPresentB .extracting(CampaignRequestBody::getUser) .extracting(CampaignRequestBodyUser::getKey) .isNotEmpty() - .isNotEqualTo("any-key"); + .doesNotContain("any-key"); } @Test @@ -1096,8 +1096,8 @@ private static BidRequest givenBidRequest(UnaryOperator impCusto private static BidRequest givenBidRequest(Imp givenImp) { return BidRequest.builder() - .device(Device.builder().ip("anyId").build()) - .imp(singletonList(givenImp)) + .device(Device.builder().ip("anyId").build()) + .imp(singletonList(givenImp)) .build(); } @@ -1111,10 +1111,11 @@ private static Imp givenImp(UnaryOperator impCustomizer, return impCustomizer.apply(Imp.builder() .id("123") .banner(Banner.builder().w(23).h(25).build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, extImpBuilder.apply(ExtImpFlipp.builder() - .publisherNameIdentifier("publisherName") - .creativeType("Any") - .zoneIds(List.of(12))) + .ext(mapper.valueToTree(ExtPrebid.of(null, extImpBuilder.apply( + ExtImpFlipp.builder() + .publisherNameIdentifier("publisherName") + .creativeType("Any") + .zoneIds(List.of(12))) .build())))) .build(); } diff --git a/src/test/java/org/prebid/server/bidder/floxis/FloxisBidderTest.java b/src/test/java/org/prebid/server/bidder/floxis/FloxisBidderTest.java new file mode 100644 index 00000000000..f94d035289f --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/floxis/FloxisBidderTest.java @@ -0,0 +1,595 @@ +package org.prebid.server.bidder.floxis; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.Audio; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Format; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.Native; +import com.iab.openrtb.request.Site; +import com.iab.openrtb.request.Video; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.junit.jupiter.api.Test; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.HttpResponse; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.floxis.ExtImpFloxis; +import org.prebid.server.proto.openrtb.ext.response.BidType; + +import java.util.List; +import java.util.function.UnaryOperator; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static java.util.function.UnaryOperator.identity; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.tuple; + +public class FloxisBidderTest extends VertxTest { + + private static final String ENDPOINT_URL = "https://{Host}.floxis.tech/pbs?seat={SeatId}"; + + private final FloxisBidder target = new FloxisBidder(ENDPOINT_URL, jacksonMapper); + + @Test + public void creationShouldFailOnInvalidEndpointUrl() { + assertThatIllegalArgumentException() + .isThrownBy(() -> new FloxisBidder("invalid_url", jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldReturnErrorWhenImpExtCouldNotBeParsed() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp + .id("imp-1") + .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode())))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input); + assertThat(error.getMessage()).startsWith("invalid imp.ext.bidder for imp imp-1:"); + }); + } + + @Test + public void makeHttpRequestsShouldUrlEscapeSeatAndUseEuHost() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("a b&c", "eu"))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://eu.floxis.tech/pbs?seat=a%20b%26c"); + } + + @Test + public void makeHttpRequestsShouldUseApacHost() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("seat-apac", "apac"))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://apac.floxis.tech/pbs?seat=seat-apac"); + } + + @Test + public void makeHttpRequestsShouldUseUseHostForExplicitUsE() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("abc", "us-e"))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://us-e.floxis.tech/pbs?seat=abc"); + } + + @Test + public void makeHttpRequestsShouldDefaultToUseHostWhenRegionMissing() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("abc", null))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://us-e.floxis.tech/pbs?seat=abc"); + } + + @Test + public void makeHttpRequestsShouldUseArbitraryValidRegionLabelAsSubdomain() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("abc", "mars"))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://mars.floxis.tech/pbs?seat=abc"); + } + + @Test + public void makeHttpRequestsShouldUsePartnerPrefixedHostWhenPartnerProvided() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("abc", "us-e", "acme"))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://acme-us-e.floxis.tech/pbs?seat=abc"); + } + + @Test + public void makeHttpRequestsShouldLeaveEndpointUnchangedWhenItDeclaresNoMacros() { + // given + final FloxisBidder bidder = new FloxisBidder("http://localhost:8090/floxis-exchange", jacksonMapper); + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("abc", "eu"))); + + // when + final Result>> result = bidder.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("http://localhost:8090/floxis-exchange"); + } + + @Test + public void makeHttpRequestsShouldRouteOnceAndForwardAllImpsWhenSeatAndRegionMatch() { + // given + final BidRequest bidRequest = BidRequest.builder() + .id("req-1") + .imp(asList( + givenImp(imp -> imp.id("imp-1").ext(givenImpExt("seat-eu", "eu"))), + givenImp(imp -> imp.id("imp-2").ext(givenImpExt("seat-eu", "eu"))))) + .site(Site.builder().id("271").build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://eu.floxis.tech/pbs?seat=seat-eu"); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getId) + .containsExactly("imp-1", "imp-2"); + } + + @Test + public void makeHttpRequestsShouldRouteOnceWhenImpsResolveToSameHostThroughDefaults() { + // given + final BidRequest bidRequest = BidRequest.builder() + .id("req-1") + .imp(asList( + givenImp(imp -> imp.id("imp-1").ext(givenImpExt("seat-us", null))), + givenImp(imp -> imp.id("imp-2").ext(givenImpExt("seat-us", "us-e", "floxis"))))) + .site(Site.builder().id("271").build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://us-e.floxis.tech/pbs?seat=seat-us"); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getId) + .containsExactly("imp-1", "imp-2"); + } + + @Test + public void makeHttpRequestsShouldRouteOnceWhenRegionCaseDiffers() { + // given + final BidRequest bidRequest = BidRequest.builder() + .id("req-1") + .imp(asList( + givenImp(imp -> imp.id("imp-1").ext(givenImpExt("seat-eu", "eu"))), + givenImp(imp -> imp.id("imp-2").ext(givenImpExt("seat-eu", "EU"))))) + .site(Site.builder().id("271").build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://eu.floxis.tech/pbs?seat=seat-eu"); + } + + @Test + public void makeHttpRequestsShouldSplitPerSeatWhenImpsShareAHost() { + // given + final BidRequest bidRequest = BidRequest.builder() + .id("req-1") + .imp(asList( + givenImp(imp -> imp.id("imp-1").ext(givenImpExt("seat-eu", "eu"))), + givenImp(imp -> imp.id("imp-2").ext(givenImpExt("seat-other", "eu"))))) + .site(Site.builder().id("271").build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(2) + .extracting(HttpRequest::getUri) + .containsExactly( + "https://eu.floxis.tech/pbs?seat=seat-eu", + "https://eu.floxis.tech/pbs?seat=seat-other"); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getId) + .containsExactly("imp-1", "imp-2"); + } + + @Test + public void makeHttpRequestsShouldSplitPerRegionWhenImpsTargetDifferentRegions() { + // given + final BidRequest bidRequest = BidRequest.builder() + .id("req-1") + .imp(asList( + givenImp(imp -> imp.id("imp-1").ext(givenImpExt("seat-eu", "eu"))), + givenImp(imp -> imp.id("imp-2").ext(givenImpExt("seat-eu", "apac"))))) + .site(Site.builder().id("271").build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(2) + .extracting(HttpRequest::getUri) + .containsExactly( + "https://eu.floxis.tech/pbs?seat=seat-eu", + "https://apac.floxis.tech/pbs?seat=seat-eu"); + } + + @Test + public void makeHttpRequestsShouldSplitPerPartnerWhenImpsTargetDifferentPartners() { + // given + final BidRequest bidRequest = BidRequest.builder() + .id("req-1") + .imp(asList( + givenImp(imp -> imp.id("imp-1").ext(givenImpExt("seat-eu", "eu", "acme"))), + givenImp(imp -> imp.id("imp-2").ext(givenImpExt("seat-eu", "eu", "other"))))) + .site(Site.builder().id("271").build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(2) + .extracting(HttpRequest::getUri) + .containsExactly( + "https://acme-eu.floxis.tech/pbs?seat=seat-eu", + "https://other-eu.floxis.tech/pbs?seat=seat-eu"); + } + + @Test + public void makeHttpRequestsShouldDropOnlyTheImpWhoseExtCouldNotBeParsed() { + // given + final BidRequest bidRequest = BidRequest.builder() + .id("req-1") + .imp(asList( + givenImp(imp -> imp.id("imp-bad") + .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode())))), + givenImp(imp -> imp.id("imp-good").ext(givenImpExt("seat-eu", "eu"))))) + .site(Site.builder().id("271").build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> assertThat(error.getMessage()) + .startsWith("invalid imp.ext.bidder for imp imp-bad:")); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://eu.floxis.tech/pbs?seat=seat-eu"); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getId) + .containsExactly("imp-good"); + } + + @Test + public void makeHttpRequestsShouldForwardRequestBodyUnchanged() { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("abc", "eu"))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .containsExactly(bidRequest); + } + + @Test + public void makeBidsShouldReturnErrorWhenResponseBodyCouldNotBeParsed() { + // given + final BidderCall httpCall = givenHttpCall(givenBidRequest(identity()), "invalid"); + + // when + final Result> result = target.makeBids(httpCall, BidRequest.builder().build()); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response)); + } + + @Test + public void makeBidsShouldReturnEmptyWhenResponseHasNoSeatBid() throws Exception { + // given + final BidderCall httpCall = givenHttpCall(givenBidRequest(identity()), + mapper.writeValueAsString(BidResponse.builder().build())); + + // when + final Result> result = target.makeBids(httpCall, BidRequest.builder().build()); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).isEmpty(); + } + + @Test + public void makeBidsShouldSkipNullSeatBidAndEmptyBids() throws Exception { + // given + final BidResponse bidResponse = BidResponse.builder() + .cur("USD") + .seatbid(asList( + null, + SeatBid.builder().bid(null).build(), + SeatBid.builder() + .bid(singletonList(Bid.builder().impid("imp-1").mtype(1).build())) + .build())) + .build(); + final BidderCall httpCall = givenHttpCall(givenBidRequest(identity()), + mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, givenBidRequest(identity())); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(BidderBid::getType) + .containsExactly(BidType.banner); + } + + @Test + public void makeBidsShouldResolveBidTypeFromMTypeAndPassCurrency() throws Exception { + // given + final BidResponse bidResponse = BidResponse.builder() + .cur("EUR") + .seatbid(singletonList(SeatBid.builder() + .bid(asList( + Bid.builder().impid("imp-1").mtype(1).build(), + Bid.builder().impid("imp-1").mtype(2).build(), + Bid.builder().impid("imp-1").mtype(3).build(), + Bid.builder().impid("imp-1").mtype(4).build())) + .build())) + .build(); + final BidderCall httpCall = givenHttpCall(givenBidRequest(identity()), + mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, givenBidRequest(identity())); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getType, BidderBid::getBidCurrency) + .containsExactly( + tuple(BidType.banner, "EUR"), + tuple(BidType.video, "EUR"), + tuple(BidType.audio, "EUR"), + tuple(BidType.xNative, "EUR")); + } + + @Test + public void makeBidsShouldReturnErrorWhenMTypeUnsupported() throws Exception { + // given + final BidResponse bidResponse = givenBidResponse(Bid.builder().impid("imp-1").mtype(7).build()); + final BidderCall httpCall = givenHttpCall(givenBidRequest(identity()), + mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, givenBidRequest(identity())); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1) + .containsOnly(BidderError.badServerResponse( + "unsupported bid.mtype 7 for impression imp-1")); + } + + @Test + public void makeBidsShouldResolveBidTypeFromSingleFormatImpWhenMTypeAbsent() throws Exception { + // given + final BidRequest bidRequest = BidRequest.builder() + .imp(asList( + Imp.builder().id("b").banner(Banner.builder().build()).build(), + Imp.builder().id("v").video(Video.builder().build()).build(), + Imp.builder().id("a").audio(Audio.builder().build()).build(), + Imp.builder().id("n").xNative(Native.builder().build()).build())) + .build(); + final BidResponse bidResponse = BidResponse.builder() + .cur("USD") + .seatbid(singletonList(SeatBid.builder() + .bid(asList( + Bid.builder().impid("b").build(), + Bid.builder().impid("v").build(), + Bid.builder().impid("a").build(), + Bid.builder().impid("n").build())) + .build())) + .build(); + final BidderCall httpCall = givenHttpCall(bidRequest, mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getType) + .containsExactly(BidType.banner, BidType.video, BidType.audio, BidType.xNative); + } + + @Test + public void makeBidsShouldReturnErrorForMultiFormatImpWithoutMType() throws Exception { + // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("imp-1") + .banner(Banner.builder().build()) + .video(Video.builder().build()) + .build())) + .build(); + final BidResponse bidResponse = givenBidResponse(Bid.builder().impid("imp-1").build()); + final BidderCall httpCall = givenHttpCall(bidRequest, mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1) + .containsOnly(BidderError.badServerResponse( + "unable to resolve a single media type for impression imp-1; set bid.mtype")); + } + + @Test + public void makeBidsShouldReturnErrorForImpWithoutFormatAndWithoutMType() throws Exception { + // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("imp-1").build())) + .build(); + final BidResponse bidResponse = givenBidResponse(Bid.builder().impid("imp-1").build()); + final BidderCall httpCall = givenHttpCall(bidRequest, mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1) + .containsOnly(BidderError.badServerResponse( + "unable to resolve a single media type for impression imp-1; set bid.mtype")); + } + + @Test + public void makeBidsShouldReturnErrorWhenBidImpIdNotFound() throws Exception { + // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("imp-1").banner(Banner.builder().build()).build())) + .build(); + final BidResponse bidResponse = givenBidResponse(Bid.builder().impid("no-such-imp").build()); + final BidderCall httpCall = givenHttpCall(bidRequest, mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1) + .containsOnly(BidderError.badServerResponse( + "unable to find impression no-such-imp for bid")); + } + + private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { + return BidRequest.builder() + .id("req-1") + .imp(singletonList(givenImp(impCustomizer))) + .site(Site.builder().id("271").build()) + .build(); + } + + private static Imp givenImp(UnaryOperator impCustomizer) { + return impCustomizer.apply(Imp.builder() + .id("imp-1") + .banner(Banner.builder().format(singletonList(Format.builder().w(300).h(250).build())).build()) + .ext(givenImpExt("pub-seat-1", null))) + .build(); + } + + private static ObjectNode givenImpExt(String seat, String region) { + return givenImpExt(seat, region, null); + } + + private static ObjectNode givenImpExt(String seat, String region, String partner) { + return mapper.valueToTree(ExtPrebid.of(null, ExtImpFloxis.of(seat, region, partner))); + } + + private static BidResponse givenBidResponse(Bid bid) { + return BidResponse.builder() + .cur("USD") + .seatbid(singletonList(SeatBid.builder().bid(singletonList(bid)).build())) + .build(); + } + + private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + return BidderCall.succeededHttp( + HttpRequest.builder().payload(bidRequest).build(), + HttpResponse.of(200, null, body), + null); + } +} diff --git a/src/test/java/org/prebid/server/bidder/huaweiads/HuaweiAdSlotBuilderTest.java b/src/test/java/org/prebid/server/bidder/huaweiads/HuaweiAdSlotBuilderTest.java index 75d2592ee55..2b5f7459539 100644 --- a/src/test/java/org/prebid/server/bidder/huaweiads/HuaweiAdSlotBuilderTest.java +++ b/src/test/java/org/prebid/server/bidder/huaweiads/HuaweiAdSlotBuilderTest.java @@ -472,9 +472,7 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasTwoMainImagesWithFo .build(), Asset.builder() .img(ImageObject.builder().w(1080).h(1920).wmin(1080).hmin(1620).type(3).build()) - .build() - ) - ) + .build())) .build(); final Imp givenImp = Imp.builder() .xNative(Native.builder().request(mapper.writeValueAsString(nativeRequest)).build()) diff --git a/src/test/java/org/prebid/server/bidder/kueezrtb/KueezRtbBidderTest.java b/src/test/java/org/prebid/server/bidder/kueezrtb/KueezRtbBidderTest.java index 334ebe2f087..65bb6f2e1d6 100644 --- a/src/test/java/org/prebid/server/bidder/kueezrtb/KueezRtbBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/kueezrtb/KueezRtbBidderTest.java @@ -205,9 +205,10 @@ private static BidRequest givenBidRequest(UnaryOperator impCusto } private static Imp givenImp(UnaryOperator impCustomizer) { - return impCustomizer.apply(Imp.builder() - .id("impId") - .ext(mapper.valueToTree(ExtPrebid.of(null, KueezRtbImpExt.of("cid"))))) + return impCustomizer.apply( + Imp.builder() + .id("impId") + .ext(mapper.valueToTree(ExtPrebid.of(null, KueezRtbImpExt.of("cid"))))) .build(); } diff --git a/src/test/java/org/prebid/server/bidder/lemmadigital/LemmaDigitalBidderTest.java b/src/test/java/org/prebid/server/bidder/lemmadigital/LemmaDigitalBidderTest.java index 5ae774939b5..4c24c9254fb 100644 --- a/src/test/java/org/prebid/server/bidder/lemmadigital/LemmaDigitalBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/lemmadigital/LemmaDigitalBidderTest.java @@ -122,7 +122,7 @@ public void makeHttpRequestsShouldReturnErrorWhenFirstImpDoesNotContainExt() { @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given - final BidderCall httpCall = givenHttpCall(null, "invalid"); + final BidderCall httpCall = givenHttpCall("invalid"); // when final Result> result = target.makeBids(httpCall, null); @@ -139,7 +139,7 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { @Test public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(null)); + final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(null)); // when final Result> result = target.makeBids(httpCall, null); @@ -152,7 +152,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProces @Test public void makeBidsShouldReturnBidderBidWithBannerWhenMediaTypeIsNotSpecified() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(givenBidResponse(identity()))); // when @@ -168,7 +168,7 @@ public void makeBidsShouldReturnBidderBidWithBannerWhenMediaTypeIsNotSpecified() public void makeBidsShouldReturnBidderBidWithVideoWhenBannerAndVideoInBidRequestSpecified() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(givenBidResponse(identity()))); // when @@ -210,9 +210,9 @@ private static BidResponse givenBidResponse(UnaryOperator bidCus .build(); } - private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), + HttpRequest.builder().payload(null).build(), HttpResponse.of(200, null, body), null); } diff --git a/src/test/java/org/prebid/server/bidder/loyal/LoyalBidderTest.java b/src/test/java/org/prebid/server/bidder/loyal/LoyalBidderTest.java index 35c8615f322..9cd2e9f0612 100644 --- a/src/test/java/org/prebid/server/bidder/loyal/LoyalBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/loyal/LoyalBidderTest.java @@ -178,7 +178,7 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCannotBeParsed() { final List errors = result.getErrors(); assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMessage()) + assertThat(errors.getFirst().getMessage()) .startsWith("found no valid impressions"); } diff --git a/src/test/java/org/prebid/server/bidder/mabidder/MabidderBidderTest.java b/src/test/java/org/prebid/server/bidder/mabidder/MabidderBidderTest.java index 3af318861b1..c20f80f8dfb 100644 --- a/src/test/java/org/prebid/server/bidder/mabidder/MabidderBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/mabidder/MabidderBidderTest.java @@ -185,6 +185,7 @@ private static BidRequest givenBidRequest() { @Value(staticConstructor = "of") private static class MabidderImpExt { + String ppid; } diff --git a/src/test/java/org/prebid/server/bidder/melozen/MeloZenBidderTest.java b/src/test/java/org/prebid/server/bidder/melozen/MeloZenBidderTest.java index ac4c21bed18..a578d46fba1 100644 --- a/src/test/java/org/prebid/server/bidder/melozen/MeloZenBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/melozen/MeloZenBidderTest.java @@ -410,10 +410,6 @@ private static String givenBidResponse(Bid... bids) throws JsonProcessingExcepti .build()); } - private static Bid givenBid(UnaryOperator bidCustomizer) { - return bidCustomizer.apply(Bid.builder()).build(); - } - private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( HttpRequest.builder().build(), diff --git a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java index b4025692372..441e1700023 100644 --- a/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/missena/MissenaBidderTest.java @@ -4,11 +4,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; +import com.iab.openrtb.request.Eid; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.Regs; import com.iab.openrtb.request.Site; import com.iab.openrtb.request.Source; import com.iab.openrtb.request.SupplyChain; +import com.iab.openrtb.request.Uid; import com.iab.openrtb.request.User; import com.iab.openrtb.response.Bid; import org.junit.jupiter.api.BeforeEach; @@ -33,7 +35,6 @@ import org.prebid.server.version.PrebidVersionProvider; import java.math.BigDecimal; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.UnaryOperator; @@ -41,6 +42,7 @@ import static java.util.Collections.singletonList; import static java.util.function.UnaryOperator.identity; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; @@ -57,7 +59,8 @@ class MissenaBidderTest extends VertxTest { private static final String ENDPOINT_URL = "https://test-url.com/?t={PublisherID}"; - private static final String TEST_PBS_VERSION = "pbs-java/1.0"; + private static final String TEST_PBS_VERSION_RECORD = "pbs-java/1.0"; + private static final String TEST_EXPECTED_VERSION = "prebid-server-java@1.0"; @Mock(strictness = LENIENT) private CurrencyConversionService currencyConversionService; @@ -75,7 +78,7 @@ public void setUp() { currencyConversionService, prebidVersionProvider); - given(prebidVersionProvider.getNameVersionRecord()).willReturn(TEST_PBS_VERSION); + given(prebidVersionProvider.getNameVersionRecord()).willReturn(TEST_PBS_VERSION_RECORD); given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) .willAnswer(invocation -> invocation.getArgument(0)); } @@ -83,7 +86,7 @@ public void setUp() { @Test public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenInvalidImpExt())); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.ext(givenInvalidImpExt()))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -98,20 +101,26 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { public void makeHttpRequestsShouldMakeRequestForFirstValidImp() { // given final ObjectNode settingsNode = mapper.createObjectNode().put("settingKey", "settingValue"); + final List userEids = List.of(Eid.builder() + .source("id-source") + .uids(List.of(Uid.builder().id("uid").atype(1).build())) + .build()); final BidRequest bidRequest = BidRequest.builder() .id("requestId") + .test(1) .tmax(500L) .cur(singletonList("USD")) .imp(List.of( givenImp(imp -> imp.id("impId1") - .ext(givenImpExt("apiKey1", "placementId1", "1", List.of("banner"), settingsNode))), + .ext(givenImpExt("apiKey1", "placementId1", "sample1", + List.of("banner"), settingsNode))), givenImp(imp -> imp.id("impId2") - .ext(givenImpExt("apiKey2", "placementId2", "0", null, null))))) + .ext(givenImpExt("apiKey2", "placementId2", "sample2", null, null))))) .site(Site.builder().page("http://test.com/page").domain("test.com").build()) .regs(Regs.builder().ext(ExtRegs.of(1, null, null, null)).build()) .user(User.builder().buyeruid("buyer1") - .ext(ExtUser.builder().consent("consentStr").build()).build()) + .ext(ExtUser.builder().consent("consentStr").eids(userEids).build()).build()) .source(Source.builder().schain(SupplyChain.of(1, null, null, null)).build()) .device(Device.builder().ua("test-ua").ip("123.123.123.123").build()) .build(); @@ -121,22 +130,25 @@ public void makeHttpRequestsShouldMakeRequestForFirstValidImp() { // then final MissenaUserParams expectedUserParams = MissenaUserParams.builder() + .apiKey("apiKey1") .formats(List.of("banner")) .placement("placementId1") - .testMode("1") + .sample("sample1") .settings(settingsNode) .build(); final MissenaAdRequest expectedPayload = MissenaAdRequest.builder() .adUnit("impId1") .currency("USD") + .debug(true) + .userEids(userEids) .floor(BigDecimal.valueOf(0.1)) .floorCurrency("USD") .idempotencyKey("requestId") .requestId("requestId") .timeout(500L) .params(expectedUserParams) - .version(TEST_PBS_VERSION) + .version(TEST_EXPECTED_VERSION) .bidRequest(bidRequest) .build(); @@ -149,12 +161,140 @@ public void makeHttpRequestsShouldMakeRequestForFirstValidImp() { .containsExactly(Collections.singleton("impId1")); } + @Test + public void makeHttpRequestsShouldPassOriginalBidRequestAsOrtb2() { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.ext(givenImpExt("apiKey")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getBidRequest) + .isEqualTo(bidRequest); + } + + @Test + public void makeHttpRequestsShouldPassUserEidsWhenPresent() { + // given + final List userEids = List.of(Eid.builder() + .source("id-source") + .uids(List.of(Uid.builder().id("uid").atype(1).build())) + .build()); + final BidRequest bidRequest = givenBidRequest( + request -> request.user(User.builder().ext(ExtUser.builder().eids(userEids).build()).build()), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getUserEids) + .isEqualTo(userEids); + } + + @Test + public void makeHttpRequestsShouldNotPassUserEidsWhenUserIsNull() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.user(null), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getUserEids) + .isNull(); + } + + @Test + public void makeHttpRequestsShouldNotPassUserEidsWhenEidsAreEmpty() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.user( + User.builder().ext(ExtUser.builder().eids(Collections.emptyList()).build()).build()), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getUserEids) + .isNull(); + } + + @Test + public void makeHttpRequestsShouldSetDebugWhenTestIsOne() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.test(1), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getDebug) + .isEqualTo(true); + } + + @Test + public void makeHttpRequestsShouldNotSetDebugWhenTestIsNotOne() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.test(0), + givenImp(imp -> imp.ext(givenImpExt("apiKey")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getDebug) + .isNull(); + } + + @Test + public void makeHttpRequestsShouldSendUnknownVersionWhenVersionRecordIsNull() { + // given + given(prebidVersionProvider.getNameVersionRecord()).willReturn(null); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.ext(givenImpExt("apiKey")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getPayload) + .extracting(MissenaAdRequest::getVersion) + .isEqualTo("prebid-server-java@unknown"); + } + @Test public void makeHttpRequestsShouldReturnErrorIfAllImpsAreInvalid() { // given final BidRequest bidRequest = givenBidRequest( - imp -> imp.ext(givenInvalidImpExt()), - imp -> imp.ext(givenInvalidImpExt())); + givenImp(imp -> imp.ext(givenInvalidImpExt())), + givenImp(imp -> imp.ext(givenInvalidImpExt()))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -169,11 +309,11 @@ public void makeHttpRequestsShouldReturnErrorIfAllImpsAreInvalid() { @Test public void makeHttpRequestsShouldReturnExpectedHeadersWhenDeviceHasIpAndIpv6() { // given - final BidRequest bidRequest = givenBidRequest(identity()) - .toBuilder() - .site(Site.builder().page("http://page.com").build()) - .device(Device.builder().ua("ua").ip("ip").ipv6("ipv6").build()) - .build(); + final BidRequest bidRequest = givenBidRequest( + request -> request + .site(Site.builder().page("http://page.com").build()) + .device(Device.builder().ua("ua").ip("ip").ipv6("ipv6").build()), + givenImp(identity())); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -195,10 +335,9 @@ public void makeHttpRequestsShouldReturnExpectedHeadersWhenDeviceHasIpAndIpv6() @Test public void makeHttpRequestsShouldReturnExpectedHeadersWhenDeviceHasIpv6Only() { // given - final BidRequest bidRequest = givenBidRequest(identity()) - .toBuilder() - .device(Device.builder().ip(null).ipv6("ipv6").build()) - .build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip(null).ipv6("ipv6").build()), + givenImp(identity())); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -244,7 +383,7 @@ public void makeHttpRequestsShouldConvertBidFloorCurrency() { @Test public void makeHttpRequestsShouldUseCorrectUri() { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.ext(givenImpExt("testApiKey"))); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.ext(givenImpExt("testApiKey")))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -260,7 +399,7 @@ public void makeHttpRequestsShouldUseCorrectUri() { public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given final BidderCall httpCall = givenHttpCall("invalid"); - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("impId1")); + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.id("impId1"))); // when final Result> result = target.makeBids(httpCall, bidRequest); @@ -281,10 +420,14 @@ public void makeBidsShouldReturnSingleBid() throws JsonProcessingException { .cpm(BigDecimal.TEN) .currency("USD") .ad("adm") + .width(320) + .height(100) .build(); final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(bidResponse)); - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("impId")).toBuilder().id("requestId").build(); + final BidRequest bidRequest = givenBidRequest( + request -> request.id("requestId"), + givenImp(imp -> imp.id("impId"))); // when final Result> result = target.makeBids(httpCall, bidRequest); @@ -298,17 +441,48 @@ public void makeBidsShouldReturnSingleBid() throws JsonProcessingException { .price(BigDecimal.TEN) .adm("adm") .crid("id") + .w(320) + .h(100) .build(); assertThat(result.getValue()).hasSize(1) .containsOnly(BidderBid.of(expectedBid, BidType.banner, "USD")); } - private static BidRequest givenBidRequest(UnaryOperator... impCustomizers) { - final List imps = Arrays.stream(impCustomizers) - .map(MissenaBidderTest::givenImp) - .toList(); - return BidRequest.builder().imp(imps).cur(singletonList("USD")).build(); + @Test + public void makeBidsShouldReturnBidWithoutSizeWhenResponseHasNoSize() throws JsonProcessingException { + // given + final MissenaAdResponse bidResponse = MissenaAdResponse.builder() + .requestId("id") + .cpm(BigDecimal.TEN) + .currency("USD") + .ad("adm") + .build(); + + final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(bidResponse)); + final BidRequest bidRequest = givenBidRequest( + request -> request.id("requestId"), + givenImp(imp -> imp.id("impId"))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getW, Bid::getH) + .containsExactly(tuple(null, null)); + } + + private static BidRequest givenBidRequest(Imp... imps) { + return givenBidRequest(identity(), imps); + } + + private static BidRequest givenBidRequest(UnaryOperator bidRequestCustomizer, + Imp... imps) { + + return bidRequestCustomizer.apply(BidRequest.builder().imp(List.of(imps)).cur(singletonList("USD"))).build(); } private static Imp givenImp(UnaryOperator impCustomizer) { @@ -326,14 +500,14 @@ private static ObjectNode givenImpExt(String apiKey) { private static ObjectNode givenImpExt(String apiKey, String placement, - String testMode, + String sample, List formats, ObjectNode settings) { final ExtImpMissena extImpMissena = ExtImpMissena.builder() .apiKey(apiKey) .placement(placement) - .testMode(testMode) + .sample(sample) .formats(formats) .settings(settings) .build(); diff --git a/src/test/java/org/prebid/server/bidder/mobkoi/MobkoiBidderTest.java b/src/test/java/org/prebid/server/bidder/mobkoi/MobkoiBidderTest.java index 4a8d59d8849..edebc8b890b 100644 --- a/src/test/java/org/prebid/server/bidder/mobkoi/MobkoiBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/mobkoi/MobkoiBidderTest.java @@ -2,13 +2,14 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.User; import com.iab.openrtb.response.Bid; -import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.junit.jupiter.api.Test; +import org.prebid.server.VertxTest; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; import org.prebid.server.bidder.model.BidderError; @@ -16,7 +17,6 @@ import org.prebid.server.bidder.model.HttpResponse; import org.prebid.server.bidder.model.Result; import org.prebid.server.proto.openrtb.ext.ExtPrebid; -import org.prebid.server.VertxTest; import org.prebid.server.proto.openrtb.ext.request.ExtUser; import org.prebid.server.proto.openrtb.ext.request.mobkoi.ExtImpMobkoi; @@ -100,7 +100,7 @@ public void makeHttpRequestsShouldOverrideTagIdWithPlacementId() { // given final ObjectNode mobkoiExt = impExt("pid"); final Imp givenImp = givenImp(impBuilder -> impBuilder.tagid("tagId").ext(mobkoiExt)); - final BidRequest bidRequest = BidRequest.builder().imp(asList(givenImp)).build(); + final BidRequest bidRequest = BidRequest.builder().imp(singletonList(givenImp)).build(); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -118,7 +118,7 @@ public void makeHttpRequestsShouldKeepOriginalTagIdWhenPlacementIdMissing() { // given final ObjectNode mobkoiExt = impExt(null); final Imp givenImp = givenImp(impBuilder -> impBuilder.tagid("tagId").ext(mobkoiExt)); - final BidRequest bidRequest = BidRequest.builder().imp(asList(givenImp)).build(); + final BidRequest bidRequest = BidRequest.builder().imp(singletonList(givenImp)).build(); // when final Result>> result = target.makeHttpRequests(bidRequest); diff --git a/src/test/java/org/prebid/server/bidder/nativery/NativeryBidderTest.java b/src/test/java/org/prebid/server/bidder/nativery/NativeryBidderTest.java index 707fd40d27a..c6aa91604ce 100644 --- a/src/test/java/org/prebid/server/bidder/nativery/NativeryBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/nativery/NativeryBidderTest.java @@ -131,7 +131,7 @@ public void makeHttpRequestsShouldPreserveOriginalExtFields() { // then assertThat(result.getErrors()).isEmpty(); - final ExtRequest resultingExt = result.getValue().get(0).getPayload().getExt(); + final ExtRequest resultingExt = result.getValue().getFirst().getPayload().getExt(); assertThat(resultingExt.getProperty("accountId").asText()).isEqualTo("acc-123"); assertThat(resultingExt.getProperty("nativery").path("widgetId").asText()).isEqualTo("widget1"); @@ -262,7 +262,7 @@ public void makeBidsShouldReturnBannerBid() throws JsonProcessingException { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - final BidderBid bidderBid = result.getValue().get(0); + final BidderBid bidderBid = result.getValue().getFirst(); assertThat(bidderBid.getType()).isEqualTo(BidType.banner); assertThat(bidderBid.getBidCurrency()).isEqualTo(DEFAULT_CURRENCY); @@ -291,7 +291,7 @@ public void makeBidsShouldReturnBannerBidForDisplayType() throws JsonProcessingE assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - final BidderBid bidderBid = result.getValue().get(0); + final BidderBid bidderBid = result.getValue().getFirst(); assertThat(bidderBid.getType()).isEqualTo(BidType.banner); assertThat(bidderBid.getBidCurrency()).isEqualTo(DEFAULT_CURRENCY); @@ -319,7 +319,7 @@ public void makeBidsShouldReturnBannerBidForRichMediaType() throws JsonProcessin assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - final BidderBid bidderBid = result.getValue().get(0); + final BidderBid bidderBid = result.getValue().getFirst(); assertThat(bidderBid.getType()).isEqualTo(banner); assertThat(bidderBid.getBidCurrency()).isEqualTo(DEFAULT_CURRENCY); @@ -348,7 +348,7 @@ public void makeBidsShouldReturnVideoBid() throws JsonProcessingException { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - final BidderBid bidderBid = result.getValue().get(0); + final BidderBid bidderBid = result.getValue().getFirst(); assertThat(bidderBid.getType()).isEqualTo(BidType.video); assertThat(bidderBid.getBidCurrency()).isEqualTo(DEFAULT_CURRENCY); @@ -377,7 +377,7 @@ public void makeBidsShouldReturnNativeBid() throws JsonProcessingException { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - final BidderBid bidderBid = result.getValue().get(0); + final BidderBid bidderBid = result.getValue().getFirst(); assertThat(bidderBid.getType()).isEqualTo(BidType.xNative); assertThat(bidderBid.getBidCurrency()).isEqualTo(DEFAULT_CURRENCY); @@ -436,7 +436,7 @@ public void makeBidsShouldAddMetadataFromNativeryExt() throws JsonProcessingExce assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - final BidderBid bidderBid = result.getValue().get(0); + final BidderBid bidderBid = result.getValue().getFirst(); assertThat(bidderBid.getType()).isEqualTo(BidType.xNative); assertThat(bidderBid.getBidCurrency()).isEqualTo(DEFAULT_CURRENCY); diff --git a/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java b/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java index a99552283f0..8fa090c5a7c 100644 --- a/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java @@ -54,7 +54,7 @@ public void makeHttpRequestsShouldReturnSingleDefaultRequest() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - assertThat(result.getValue().get(0).getPayload()).isEqualTo(bidRequest); + assertThat(result.getValue().getFirst().getPayload()).isEqualTo(bidRequest); } @Test @@ -188,7 +188,7 @@ public void makeBidsShouldEnrichBidExtWithRendererVersionWhenNativoRendererIsPre assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - final ObjectNode resultExt = result.getValue().get(0).getBid().getExt(); + final ObjectNode resultExt = result.getValue().getFirst().getBid().getExt(); assertThat(resultExt.get("prebid").get("meta").get("rendererVersion").textValue()).isEqualTo("1.2.3"); } @@ -212,7 +212,7 @@ public void makeBidsShouldPreserveExistingMetaFieldsWhenAddingRendererVersion() assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - final ObjectNode resultExt = result.getValue().get(0).getBid().getExt(); + final ObjectNode resultExt = result.getValue().getFirst().getBid().getExt(); assertThat(resultExt.get("prebid").get("meta").get("adaptercode").textValue()).isEqualTo("nativo"); assertThat(resultExt.get("prebid").get("meta").get("rendererVersion").textValue()).isEqualTo("2.0.0"); } @@ -234,7 +234,7 @@ public void makeBidsShouldCreateMetaWhenBidExtHasNoPrebidFieldAndNativoRendererI assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - final ObjectNode resultExt = result.getValue().get(0).getBid().getExt(); + final ObjectNode resultExt = result.getValue().getFirst().getBid().getExt(); assertThat(resultExt.get("prebid").get("meta").get("rendererVersion").textValue()).isEqualTo("3.0.0"); } @@ -261,7 +261,7 @@ public void makeBidsShouldReturnErrorAndOriginalBidWhenBidExtCannotBeParsed() assertThat(error.getMessage()).contains("Invalid ext passed in bid with id: bid1"); }); assertThat(result.getValue()).hasSize(1); - assertThat(result.getValue().get(0).getBid().getExt()).isEqualTo(invalidExt); + assertThat(result.getValue().getFirst().getBid().getExt()).isEqualTo(invalidExt); } private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { diff --git a/src/test/java/org/prebid/server/bidder/playdigo/PlaydigoBidderTest.java b/src/test/java/org/prebid/server/bidder/playdigo/PlaydigoBidderTest.java index d209487e28c..430a28ea188 100644 --- a/src/test/java/org/prebid/server/bidder/playdigo/PlaydigoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/playdigo/PlaydigoBidderTest.java @@ -140,7 +140,7 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCannotBeParsed() { final List errors = result.getErrors(); assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMessage()) + assertThat(errors.getFirst().getMessage()) .startsWith("found no valid impressions"); } diff --git a/src/test/java/org/prebid/server/bidder/preciso/PrecisoBidderTest.java b/src/test/java/org/prebid/server/bidder/preciso/PrecisoBidderTest.java index b6784daaed0..98b091d23d9 100644 --- a/src/test/java/org/prebid/server/bidder/preciso/PrecisoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/preciso/PrecisoBidderTest.java @@ -57,7 +57,7 @@ public void creationShouldFailOnInvalidEndpointUrl() { assertThatIllegalArgumentException() .isThrownBy(() -> new PrecisoBidder( - "invalid_url", currencyConversionService, jacksonMapper)); + "invalid_url", currencyConversionService, jacksonMapper)); } @@ -65,7 +65,7 @@ public void creationShouldFailOnInvalidEndpointUrl() { public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given - final BidderCall httpCall = givenHttpCall(null, "invalid"); + final BidderCall httpCall = givenHttpCall("invalid"); // when final Result> result = target.makeBids(httpCall, null); @@ -82,7 +82,7 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(null)); // when @@ -97,7 +97,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProces public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(BidResponse.builder().build())); // when @@ -112,7 +112,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws Jso @Test public void makeBidsShouldReturnBannerBid() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(givenBidResponse(bid -> bid.ext(givenBidExt(BidType.banner))))); // when @@ -129,12 +129,15 @@ public void makeBidsShouldReturnBannerBid() throws JsonProcessingException { public void makeHttpRequestsShouldConvertCurrencyIfRequestCurrencyDoesNotMatchBidderCurrency() { // given given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) - .willReturn(BigDecimal.TEN); + .willReturn(BigDecimal.TEN); final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(Imp.builder().bidfloor(BigDecimal.ONE).bidfloorcur("EUR") - .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createObjectNode()))).build())) - .id("request_id").build(); + .imp(singletonList(Imp.builder() + .bidfloor(BigDecimal.ONE) + .bidfloorcur("EUR") + .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createObjectNode()))) + .build())) + .id("request_id").build(); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -142,9 +145,9 @@ public void makeHttpRequestsShouldConvertCurrencyIfRequestCurrencyDoesNotMatchBi // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1).extracting(HttpRequest::getPayload) - .flatExtracting(BidRequest::getImp) - .extracting(Imp::getBidfloor, Imp::getBidfloorcur) - .containsOnly(tuple(BigDecimal.TEN, "USD")); + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsOnly(tuple(BigDecimal.TEN, "USD")); } @@ -152,9 +155,11 @@ public void makeHttpRequestsShouldConvertCurrencyIfRequestCurrencyDoesNotMatchBi public void makeHttpRequestsShouldTakePriceFloorsWhenBidfloorParamIsAlsoPresent() { // given final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(Imp.builder().bidfloor(BigDecimal.TEN).bidfloorcur("USD") - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpPreciso.builder() - .bidFloor(BigDecimal.ONE).build()))) + .imp(singletonList(Imp.builder() + .bidfloor(BigDecimal.TEN) + .bidfloorcur("USD") + .ext(mapper.valueToTree(ExtPrebid.of( + null, ExtImpPreciso.builder().bidFloor(BigDecimal.ONE).build()))) .build())) .id("request_id").build(); @@ -164,8 +169,8 @@ public void makeHttpRequestsShouldTakePriceFloorsWhenBidfloorParamIsAlsoPresent( // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1).extracting(HttpRequest::getPayload) - .flatExtracting(BidRequest::getImp) - .extracting(Imp::getBidfloor, Imp::getBidfloorcur).containsOnly(tuple(BigDecimal.TEN, "USD")); + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur).containsOnly(tuple(BigDecimal.TEN, "USD")); } @@ -173,11 +178,10 @@ public void makeHttpRequestsShouldTakePriceFloorsWhenBidfloorParamIsAlsoPresent( public void makeHttpRequestsShouldTakeBidfloorExtImpParamIfNoBidfloorInRequest() { // given final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(Imp.builder() - .ext(mapper.valueToTree( - ExtPrebid.of(null, ExtImpPreciso.builder() - .bidFloor(BigDecimal.valueOf(16)).build()))) - .build())) + .imp(singletonList(Imp.builder() + .ext(mapper.valueToTree(ExtPrebid.of( + null, ExtImpPreciso.builder().bidFloor(BigDecimal.valueOf(16)).build()))) + .build())) .id("request_id").build(); // when @@ -186,8 +190,8 @@ public void makeHttpRequestsShouldTakeBidfloorExtImpParamIfNoBidfloorInRequest() // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1).extracting(HttpRequest::getPayload) - .flatExtracting(BidRequest::getImp) - .extracting(Imp::getBidfloor).containsExactly(BigDecimal.valueOf(16)); + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor).containsExactly(BigDecimal.valueOf(16)); } @@ -195,12 +199,16 @@ public void makeHttpRequestsShouldTakeBidfloorExtImpParamIfNoBidfloorInRequest() public void makeHttpRequestsShouldReturnErrorMessageOnFailedCurrencyConversion() { // given given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) - .willThrow(PreBidException.class); + .willThrow(PreBidException.class); final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").bidfloor(BigDecimal.ONE).bidfloorcur("EUR") - .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createObjectNode()))).build())) - .id("request_id").build(); + .imp(singletonList(Imp.builder() + .id("123") + .bidfloor(BigDecimal.ONE) + .bidfloorcur("EUR") + .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createObjectNode()))).build())) + .id("request_id") + .build(); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -222,11 +230,11 @@ private static BidResponse givenBidResponse(Function givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), - HttpResponse.of(200, null, body), - null); + HttpRequest.builder().payload(null).build(), + HttpResponse.of(200, null, body), + null); } private static ObjectNode givenBidExt(BidType bidType) { diff --git a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java index e5211193ed9..0d7b50e89a9 100644 --- a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java @@ -388,7 +388,7 @@ public void makeHttpRequestsShouldReturnNothingWhenAlternateBidderCodeIsAbsent() public void makeHttpRequestsShouldMergeWrappersFromImpAndBidRequestExt() { // given final BidRequest bidRequest = givenBidRequest( - bidRequestBuilder -> bidRequestBuilder.ext(givenBidRequestExt(123, null)), + bidRequestBuilder -> bidRequestBuilder.ext(givenBidRequestExt(123)), identity(), extBuilder -> extBuilder.wrapper(PubmaticWrapper.of(321, 456))); @@ -1560,10 +1560,10 @@ private ObjectNode givenExtImpWithKadfloor(String kadfloor) { return mapper.valueToTree(ExtPrebid.of(null, ExtImpPubmatic.builder().kadfloor(kadfloor).build())); } - private static ExtRequest givenBidRequestExt(Integer wrapperProfile, Integer wrapperVersion) { + private static ExtRequest givenBidRequestExt(Integer wrapperProfile) { final ObjectNode pubmaticNode = mapper.createObjectNode() .set("pubmatic", mapper.createObjectNode() - .set("wrapper", mapper.valueToTree(PubmaticWrapper.of(wrapperProfile, wrapperVersion)))); + .set("wrapper", mapper.valueToTree(PubmaticWrapper.of(wrapperProfile, null)))); return ExtRequest.of(ExtRequestPrebid.builder().bidderparams(pubmaticNode).build()); } diff --git a/src/test/java/org/prebid/server/bidder/readpeak/ReadPeakBidderTest.java b/src/test/java/org/prebid/server/bidder/readpeak/ReadPeakBidderTest.java index 82bee3c6893..1cb1cec2808 100644 --- a/src/test/java/org/prebid/server/bidder/readpeak/ReadPeakBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/readpeak/ReadPeakBidderTest.java @@ -134,7 +134,7 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCannotBeParsed() { final List errors = result.getErrors(); assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMessage()) + assertThat(errors.getFirst().getMessage()) .startsWith("Failed to find compatible impressions for request"); } diff --git a/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java b/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java index 7a4e483303c..116ebe97695 100644 --- a/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.App; import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Deal; @@ -177,8 +178,8 @@ public void makeHttpRequestsShouldNotReturnErrorIfNativePresent() { // given final BidRequest bidRequest = givenBidRequest( impBuilder -> impBuilder.id("123") - .banner(null) - .xNative(Native.builder().build())); + .banner(null) + .xNative(Native.builder().build())); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -189,10 +190,10 @@ public void makeHttpRequestsShouldNotReturnErrorIfNativePresent() { } @Test - public void makeHttpRequestsShouldCreateSiteAndPublisherWhenBidRequestHasNoSite() { + public void makeHttpRequestsShouldNotCreateSiteWhenBidRequestHasAppOnly() { // given final BidRequest bidRequest = givenBidRequest( - bidReq -> bidReq.site(null), + bidReq -> bidReq.site(null).app(App.builder().id("app_id").build()), identity(), identity()); @@ -204,12 +205,31 @@ public void makeHttpRequestsShouldCreateSiteAndPublisherWhenBidRequestHasNoSite( assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) .extracting(BidRequest::getSite) - .allSatisfy(site -> { - assertThat(site).isNotNull(); - assertThat(site.getPublisher()).isNotNull(); - assertThat(site.getPublisher().getExt()).isNotNull(); + .containsOnlyNulls(); + } - final JsonNode prebidNode = site.getPublisher().getExt().getProperty("prebid"); + @Test + public void makeHttpRequestsShouldAddPublisherToAppWhenBidRequestHasAppOnly() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.site(null).app(App.builder().id("app_id").build()), + identity(), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getApp) + .allSatisfy(app -> { + assertThat(app.getId()).isEqualTo("app_id"); + assertThat(app.getPublisher()).isNotNull(); + assertThat(app.getPublisher().getExt()).isNotNull(); + + final JsonNode prebidNode = app.getPublisher().getExt().getProperty("prebid"); assertThat(prebidNode).isNotNull(); assertThat(prebidNode.get("publisherId").asText()).isEqualTo("publisherId"); }); @@ -236,8 +256,10 @@ public void makeHttpRequestsShouldAddPublisherToExistingSiteWhenNoPublisher() { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getSite) - .allSatisfy(site -> { + .allSatisfy(payload -> { + assertThat(payload.getApp()).isNull(); + + final Site site = payload.getSite(); assertThat(site.getId()).isEqualTo("site_id"); assertThat(site.getName()).isEqualTo("site_name"); assertThat(site.getDomain()).isEqualTo("example.com"); @@ -557,8 +579,8 @@ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws Jso public void makeBidsShouldReturnBannerBidIfBannerIsPresent() throws JsonProcessingException { // given final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").build())) - .build(); + .imp(singletonList(Imp.builder().id("123").build())) + .build(); final BidderCall httpCall = givenHttpCall( bidRequest, mapper.writeValueAsString( @@ -602,8 +624,8 @@ public void makeBidsShouldParseNativeAdmData() throws JsonProcessingException { // given final BidRequest bidRequest = givenBidRequest( impBuilder -> impBuilder.id("123") - .banner(null) - .xNative(Native.builder().build())); + .banner(null) + .xNative(Native.builder().build())); final ObjectNode admNode = mapper.createObjectNode(); final ObjectNode nativeNode = mapper.createObjectNode(); nativeNode.put("property1", "value1"); diff --git a/src/test/java/org/prebid/server/bidder/scalibur/ScaliburBidderTest.java b/src/test/java/org/prebid/server/bidder/scalibur/ScaliburBidderTest.java new file mode 100644 index 00000000000..1c334d6649b --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/scalibur/ScaliburBidderTest.java @@ -0,0 +1,971 @@ +package org.prebid.server.bidder.scalibur; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import com.iab.openrtb.request.Audio; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.Video; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import lombok.SneakyThrows; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.HttpResponse; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.ExtRequest; +import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; +import org.prebid.server.proto.openrtb.ext.request.scalibur.ExtImpScalibur; +import org.prebid.server.proto.openrtb.ext.response.BidType; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.UnaryOperator; + +import static java.util.Collections.singletonList; +import static java.util.function.UnaryOperator.identity; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.BDDMockito.given; + +@ExtendWith(MockitoExtension.class) +class ScaliburBidderTest extends VertxTest { + + private static final String ENDPOINT_URL = "https://{Host}.test.endpoint.com"; + private static final String DEFAULT_BID_CURRENCY = "USD"; + private static final String VAST_XML = """ + """; + + @Mock + private CurrencyConversionService currencyConversionService; + + private ScaliburBidder target; + + @BeforeEach + public void setUp() { + target = new ScaliburBidder(ENDPOINT_URL, currencyConversionService, jacksonMapper); + } + + @Test + public void creationShouldFailOnInvalidEndpointUrl() { + assertThatIllegalArgumentException().isThrownBy(() -> + new ScaliburBidder("invalid_url", currencyConversionService, jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldReturnErrorsWithoutRequestWhenAllImpsAreInvalid() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1); + } + + @Test + public void makeHttpRequestsShouldAddErrorsOnInvalidImps() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode())))), + givenImp(imp -> imp.ext( + givenImpExt(ExtImpScalibur.of(null, null, DEFAULT_BID_CURRENCY, null)))), + givenImp(imp -> imp.ext( + givenImpExt(ExtImpScalibur.of("", null, DEFAULT_BID_CURRENCY, null)))), + // valid imps + givenImp(identity()), + givenImp(imp -> imp.tagid("test-tag").ext( + givenImpExt(ExtImpScalibur.of(null, null, DEFAULT_BID_CURRENCY, null)))), + givenImp(imp -> imp.tagid("test-tag").ext( + givenImpExt(ExtImpScalibur.of("", null, DEFAULT_BID_CURRENCY, null)))), + givenImp(imp -> imp.ext( + givenImpExt(ExtImpScalibur.of("placementId", null, null, null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .hasSize(4); + assertThat(result.getErrors()) + .extracting(BidderError::getMessage) + .hasSize(3) + .satisfies(errors -> { + assertThat(errors.get(0)).startsWith("Cannot deserialize value of type"); + assertThat(errors.get(1)).isEqualTo( + "imp 123: missing placement; set imp.tagid or the placementId param"); + assertThat(errors.get(2)).isEqualTo( + "imp 123: missing placement; set imp.tagid or the placementId param"); + }); + } + + @Test + public void makeHttpRequestsShouldPreferImpTagIdOverPlacementId() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .tagid("tagId") + .ext(givenImpExt(ExtImpScalibur.of("placementId", null, null, null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .singleElement() + .extracting(Imp::getTagid) + .isEqualTo("tagId"); + } + + @Test + public void makeHttpRequestsShouldUsePlacementIdWhenImpTagIdIsMissing() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .tagid(null) + .ext(givenImpExt(ExtImpScalibur.of("placementId", null, null, null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .singleElement() + .extracting(Imp::getTagid) + .isEqualTo("placementId"); + } + + @Test + public void makeHttpRequestsShouldConvertBidFloorIfCurrencyIsDifferent() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.bidfloor(BigDecimal.TEN).bidfloorcur("EUR"))); + + given(currencyConversionService.convertCurrency(BigDecimal.TEN, bidRequest, "EUR", DEFAULT_BID_CURRENCY)) + .willReturn(BigDecimal.ONE); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsExactly(tuple(BigDecimal.ONE, DEFAULT_BID_CURRENCY)); + } + + @Test + public void makeHttpRequestsShouldNotConvertBidfloorAndAssignUSDCurrencyWhenBidfloorHasEmptyCurrency() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.bidfloor(BigDecimal.TEN).bidfloorcur(null))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsExactly(tuple(BigDecimal.TEN, DEFAULT_BID_CURRENCY)); + } + + @Test + public void makeHttpRequestsShouldOverrideBidfloorAndCurrencyWhenScaliburBidFloorIsValid() { + // given + + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .bidfloor(BigDecimal.TEN) + .bidfloorcur("EUR") + .ext(givenImpExt( + ExtImpScalibur.of("placementId", BigDecimal.ONE, DEFAULT_BID_CURRENCY, null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsExactly(tuple(BigDecimal.ONE, DEFAULT_BID_CURRENCY)); + } + + @Test + public void makeHttpRequestsShouldNotOverrideBidfloorAndCurrencyWhenScaliburBidFloorIsInvalid() { + // given + + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.bidfloor(BigDecimal.TEN).bidfloorcur(DEFAULT_BID_CURRENCY) + .ext(givenImpExt(ExtImpScalibur.of("placementId", null, "EUR", null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsExactly(tuple(BigDecimal.TEN, DEFAULT_BID_CURRENCY)); + } + + @Test + public void makeHttpRequestsShouldFallbackToImpCurrencyWhenScaliburCurrencyIsMissing() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.bidfloor(BigDecimal.TEN).bidfloorcur("EUR") + .ext(givenImpExt(ExtImpScalibur.of("placementId", BigDecimal.ONE, null, null))))); + + given(currencyConversionService.convertCurrency(BigDecimal.ONE, bidRequest, "EUR", DEFAULT_BID_CURRENCY)) + .willReturn(BigDecimal.valueOf(2)); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsExactly(tuple(BigDecimal.valueOf(2), DEFAULT_BID_CURRENCY)); + } + + @Test + public void makeHttpRequestsShouldNotSetPlacementIdInImpExt() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .ext(givenImpExt(ExtImpScalibur.of("placementId", null, null, null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .containsExactly(mapper.valueToTree(ExtImpScalibur.of(null, null, null, null))); + } + + @Test + public void makeHttpRequestsShouldExtractBidderParamsAndKeepFloorAndGpid() { + // given + final ObjectNode impExt = givenImpExt( + ExtImpScalibur.of("placementId", BigDecimal.ONE, DEFAULT_BID_CURRENCY, "host")); + ((ObjectNode) impExt.get("bidder")).put("extraField", "test-custom"); + impExt.put("gpid", "test-gpid"); + impExt.put("random", "test-random"); + + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.ext(impExt))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .containsExactly( + mapper.createObjectNode() + .put("bidfloor", BigDecimal.ONE) + .put("bidfloorcur", DEFAULT_BID_CURRENCY) + .put("extraField", "test-custom") + .put("gpid", "test-gpid")); + } + + @Test + public void makeHttpRequestsShouldFillVideoDefaultValues() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .banner(null) + .video(Video.builder().build()))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(HttpRequest::getPayload) + .satisfies(request -> assertThat(request.getImp()) + .singleElement() + .extracting(Imp::getVideo) + .satisfies(video -> { + assertThat(video.getMimes()).containsExactly("video/mp4"); + assertThat(video.getMinduration()).isEqualTo(1); + assertThat(video.getMaxduration()).isEqualTo(180); + assertThat(video.getMaxbitrate()).isEqualTo(30_000); + assertThat(video.getProtocols()).containsExactly(2, 3, 5, 6); + assertThat(video.getW()).isEqualTo(640); + assertThat(video.getH()).isEqualTo(480); + assertThat(video.getPlacement()).isEqualTo(1); + assertThat(video.getLinearity()).isEqualTo(1); + })); + } + + @Test + public void makeHttpRequestsShouldPreserveProvidedVideoValues() { + // given + final Video video = Video.builder() + .mimes(List.of("video/webm")) + .minduration(10) + .maxduration(30) + .maxbitrate(5000) + .protocols(List.of(1, 2)) + .w(1280) + .h(720) + .placement(2) + .linearity(2) + .build(); + + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .banner(null) + .video(video))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(HttpRequest::getPayload) + .satisfies() + .satisfies(request -> assertThat(request.getImp()) + .singleElement() + .extracting(Imp::getVideo) + .isEqualTo(video)); + } + + @Test + public void makeHttpRequestsShouldSetIsDebugWhenTestIsEnabled() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(identity())) + .toBuilder() + .test(1) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getExt) + .satisfies(ext -> assertThat(ext.getProperty("isDebug").asInt()).isEqualTo(1)); + } + + @Test + public void makeHttpRequestsShouldSetIsDebugWhenPrebidDebugIsEnabled() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(identity())) + .toBuilder() + .ext(ExtRequest.of(ExtRequestPrebid.builder().debug(1).build())) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getExt) + .satisfies(ext -> assertThat(ext.getProperty("isDebug").asInt()).isEqualTo(1)); + } + + @Test + public void makeHttpRequestsShouldRemoveRequestExtWhenDebugIsDisabled() { + // given + final ExtRequest extRequest = ExtRequest.empty(); + extRequest.addProperty("random", TextNode.valueOf("test-random")); + + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp)) + .toBuilder() + .ext(extRequest) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getExt) + .isNull(); + } + + @Test + public void makeHttpRequestsShouldUseDefaultHostWhenHostIsMissing() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(identity()), + givenImp(imp -> imp.ext(givenImpExtWithHost(""))) + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(HttpRequest::getUri) + .isEqualTo("https://srv.test.endpoint.com"); + } + + @Test + public void makeHttpRequestsShouldGroupMultipleImpsUnderSameHost() { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.id("123").ext(givenImpExtWithHost("host1"))), + givenImp(imp -> imp.id("456").ext(givenImpExtWithHost("host2"))), + givenImp(imp -> imp.id("789").ext(givenImpExtWithHost("host1")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(2); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getImp) + .extracting(imps -> imps.stream().map(Imp::getId).toList()) + .containsExactlyInAnyOrder(List.of("123", "789"), List.of("456")); + } + + @Test + public void makeBidsShouldReturnBidsFromAllSeatBids() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(identity()), + givenImp(imp -> imp.id("456"))); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder.id("bid-1").impid("123"), + bidBuilder -> bidBuilder.id("bid-2").impid("456")))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getId) + .containsExactly("bid-1", "bid-2"); + } + + @Test + public void makeBidsShouldUseUsdCurrencyWhenResponseCurrencyIsMissing() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.id("bid-1").impid("123")))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getBidCurrency) + .isEqualTo(DEFAULT_BID_CURRENCY); + } + + @Test + public void makeBidsShouldUseResponseCurrency() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidResponse bidResponse = givenBidResponse(bidBuilder -> bidBuilder.id("bid-1").impid("123")).toBuilder() + .cur("EUR") + .build(); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getBidCurrency) + .isEqualTo("EUR"); + } + + @Test + public void makeBidsShouldRejectInvalidBidImpId() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("invalid-imp")))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()) + .singleElement() + .extracting(BidderError::getMessage) + .isEqualTo("Invalid bid imp ID invalid-imp"); + } + + @Test + public void makeBidsShouldResolveBannerBidTypeFromMtype() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .mtype(1)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getType) + .isEqualTo(BidType.banner); + } + + @Test + public void makeBidsShouldResolveVideoBidTypeFromMtype() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(imp -> imp.banner(null).video(Video.builder().build()))); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .mtype(2)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getType) + .isEqualTo(BidType.video); + } + + @Test + public void makeBidsShouldResolveBidTypeFromImpWhenMtypeIsMissing() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.banner(Banner.builder().w(1).h(1).build()).video(null))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .mtype(null)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getType) + .isEqualTo(BidType.banner); + } + + @Test + public void makeBidsShouldResolveVideoBidTypeFromVideoImpWhenMtypeIsMissing() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.banner(null).video(Video.builder().build()))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .mtype(null)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getType) + .isEqualTo(BidType.video); + } + + @Test + public void makeBidsShouldRecoverMediaTypeFromImpWhenMtypeIsInvalid() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .mtype(3)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getType) + .isEqualTo(BidType.banner); + } + + @Test + public void makeBidsShouldRejectAmbiguousImpMediaType() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .banner(Banner.builder().w(1).h(1).build()) + .video(Video.builder().build()))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .mtype(null)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()) + .singleElement() + .extracting(BidderError::getMessage) + .isEqualTo("Unsupported or ambiguous media type for bid id=bid-1"); + } + + @Test + public void makeBidsShouldRejectInvalidMediaType() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp + .banner(null) + .audio(Audio.builder().build()))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .mtype(3)))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()) + .singleElement() + .extracting(BidderError::getMessage) + .isEqualTo("Unsupported or ambiguous media type for bid id=bid-1"); + } + + @Test + public void makeBidsShouldReplaceAdmWithVastXml() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.banner(null).video(Video.builder().build()))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .ext(mapper.createObjectNode().put("vastXml", "test"))))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getBid) + .extracting(Bid::getAdm) + .isEqualTo("test"); + } + + @Test + public void makeBidsShouldReplaceNotPresentAdmWithVastUrlWrapper() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.banner(null).video(Video.builder().build()))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .ext(mapper.createObjectNode().put("vastUrl", "https://test.com"))))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getBid) + .extracting(Bid::getAdm) + .isEqualTo(VAST_XML.formatted("https://test.com")); + } + + @Test + public void makeBidsShouldPrioritizeVastXmlOverVastUrlWhenBothArePresent() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.banner(null).video(Video.builder().build()))); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .ext(mapper.createObjectNode() + .put("vastXml", "test") + .put("vastUrl", "https://test.com"))))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getBid) + .extracting(Bid::getAdm) + .isEqualTo("test"); + } + + @Test + public void makeBidsShouldPreserveAdmWhenVastUrlIsPresent() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + givenImp(imp -> imp.banner(null).video(Video.builder().build()))); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder + .id("bid-1") + .impid("123") + .adm("test-adm") + .ext(mapper.createObjectNode().put("vastUrl", "https://test.com"))))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .singleElement() + .extracting(BidderBid::getBid) + .extracting(Bid::getAdm) + .isEqualTo("test-adm"); + } + + @Test + public void makeBidsShouldReturnEmptyResultWhenResponseHasNoSeatBids() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidResponse bidResponse = BidResponse.builder() + .seatbid(Collections.emptyList()) + .build(); + + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { + // given + final BidderCall httpCall = givenHttpCall(givenBidRequest(givenImp(identity())), "invalid"); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).allMatch(error -> error.getType() == BidderError.Type.bad_server_response + && error.getMessage().startsWith("Failed to decode: Unrecognized token")); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnValidBidsAndErrorsForInvalidBids() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(givenImp(identity())); + final BidderCall httpCall = givenHttpCall( + bidRequest, + mapper.writeValueAsString( + givenBidResponse( + bidBuilder -> bidBuilder.id("valid-bid").impid("123"), + bidBuilder -> bidBuilder.id("invalid-bid").impid("invalid-imp")))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getValue()) + .extracting(BidderBid::getBid) + .extracting(Bid::getId) + .containsExactly("valid-bid"); + + assertThat(result.getErrors()) + .singleElement() + .extracting(BidderError::getMessage) + .isEqualTo("Invalid bid imp ID invalid-imp"); + } + + private static BidRequest givenBidRequest(Imp... imps) { + return BidRequest.builder() + .cur(List.of("USD")) + .imp(Arrays.stream(imps).toList()) + .build(); + } + + private static Imp givenImp(UnaryOperator impCustomizer) { + return impCustomizer.apply(Imp.builder() + .id("123") + .banner(Banner.builder().w(1).h(1).build()) + .ext(givenImpExt(ExtImpScalibur.of("placementId", null, null, null)))) + .build(); + } + + private static ObjectNode givenImpExtWithHost(String host) { + return givenImpExt(ExtImpScalibur.of("placementId", null, null, host)); + } + + private static ObjectNode givenImpExt(ExtImpScalibur extImpScalibur) { + return mapper.valueToTree(ExtPrebid.of(null, extImpScalibur)); + } + + @SafeVarargs + @SneakyThrows + private BidResponse givenBidResponse(UnaryOperator... bidCustomizers) { + return BidResponse.builder() + .seatbid(singletonList(SeatBid.builder() + .bid(Arrays.stream(bidCustomizers) + .map(bidCustomizer -> bidCustomizer.apply(Bid.builder()).build()) + .toList()) + .build())) + .build(); + } + + private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + return BidderCall.succeededHttp( + HttpRequest.builder().payload(bidRequest).build(), + HttpResponse.of(200, null, body), + null); + } +} diff --git a/src/test/java/org/prebid/server/bidder/seedtag/SeedtagBidderTest.java b/src/test/java/org/prebid/server/bidder/seedtag/SeedtagBidderTest.java index e16d40f46b4..c0385e2d418 100644 --- a/src/test/java/org/prebid/server/bidder/seedtag/SeedtagBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/seedtag/SeedtagBidderTest.java @@ -77,7 +77,7 @@ public void makeHttpRequestsShouldMakeOneRequestWithAllImps() { // then assertThat(result.getErrors()).isEmpty(); - final BidRequest outgoingRequest = result.getValue().get(0).getPayload(); + final BidRequest outgoingRequest = result.getValue().getFirst().getPayload(); assertThat(outgoingRequest.getImp()).hasSize(2); assertThat(outgoingRequest.getCur()).containsExactly("USD"); } @@ -143,7 +143,7 @@ public void makeHttpRequestsShouldSucceedWithPublisherIdAndRonIdIntegrationType( // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - assertThat(result.getValue().get(0).getPayload().getImp()).hasSize(1); + assertThat(result.getValue().getFirst().getPayload().getImp()).hasSize(1); } @Test diff --git a/src/test/java/org/prebid/server/bidder/sevio/SevioBidderTest.java b/src/test/java/org/prebid/server/bidder/sevio/SevioBidderTest.java new file mode 100644 index 00000000000..8a026f91ae4 --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/sevio/SevioBidderTest.java @@ -0,0 +1,219 @@ +package org.prebid.server.bidder.sevio; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.junit.jupiter.api.Test; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.HttpResponse; +import org.prebid.server.bidder.model.Result; + +import java.util.Arrays; +import java.util.List; +import java.util.function.UnaryOperator; + +import static java.util.Collections.singletonList; +import static java.util.function.UnaryOperator.identity; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; +import static org.prebid.server.proto.openrtb.ext.response.BidType.xNative; +import static org.prebid.server.util.HttpUtil.ACCEPT_HEADER; +import static org.prebid.server.util.HttpUtil.APPLICATION_JSON_CONTENT_TYPE; +import static org.prebid.server.util.HttpUtil.CONTENT_TYPE_HEADER; +import static org.prebid.server.util.HttpUtil.X_OPENRTB_VERSION_HEADER; +import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE; + +public class SevioBidderTest extends VertxTest { + + private static final String ENDPOINT_URL = "https://req.adx.ws/rtb"; + + private final SevioBidder target = new SevioBidder(ENDPOINT_URL, jacksonMapper); + + @Test + public void creationShouldFailOnInvalidEndpointUrl() { + assertThatIllegalArgumentException().isThrownBy(() -> new SevioBidder("invalid_url", jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldReturnExpectedRequestWithAllImps() { + // given + final BidRequest bidRequest = givenBidRequest( + imp -> imp.id("impId1"), + imp -> imp.id("impId2")); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .satisfies(request -> assertThat(request.getBody()) + .isEqualTo(jacksonMapper.encodeToBytes(bidRequest))) + .satisfies(request -> assertThat(request.getPayload()) + .isEqualTo(bidRequest)) + .satisfies(request -> assertThat(request.getImpIds()) + .containsExactlyInAnyOrder("impId1", "impId2")); + } + + @Test + public void makeHttpRequestsShouldReturnExpectedHeaders() { + // given + final BidRequest bidRequest = givenBidRequest( + imp -> imp.id("impId1"), + imp -> imp.id("impId2")); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getHeaders) + .satisfies(headers -> assertThat(headers.get(CONTENT_TYPE_HEADER)) + .isEqualTo(APPLICATION_JSON_CONTENT_TYPE)) + .satisfies(headers -> assertThat(headers.get(ACCEPT_HEADER)) + .isEqualTo(APPLICATION_JSON_VALUE)) + .satisfies(headers -> assertThat(headers.get(X_OPENRTB_VERSION_HEADER)) + .isEqualTo("2.6")); + } + + @Test + public void makeHttpRequestsShouldUseCorrectUri() { + // given + final BidRequest bidRequest = givenBidRequest(identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getUri) + .isEqualTo(ENDPOINT_URL); + } + + @Test + public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { + // given + final BidderCall httpCall = givenHttpCall("invalid"); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response); + assertThat(error.getMessage()).startsWith("Failed to decode: Unrecognized token"); + }); + } + + @Test + public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(BidResponse.builder().build())); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnBannerBidWhenMtypeIsBanner() throws JsonProcessingException { + // given + final Bid bannerBid = Bid.builder().impid("1").mtype(1).build(); + + final BidderCall httpCall = givenHttpCall(givenBidResponse(bannerBid)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsOnly(BidderBid.of(bannerBid, banner, "USD")); + } + + @Test + public void makeBidsShouldReturnNativeBidWhenMtypeIsNative() throws JsonProcessingException { + // given + final Bid nativeBid = Bid.builder().impid("4").mtype(4).build(); + + final BidderCall httpCall = givenHttpCall(givenBidResponse(nativeBid)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsOnly(BidderBid.of(nativeBid, xNative, "USD")); + } + + @Test + public void makeBidsShouldReturnErrorWhenMtypeIsNotSupported() throws JsonProcessingException { + // given + final Bid bannerBid = Bid.builder().impid("id").mtype(1).build(); + final Bid audioBid = Bid.builder().impid("id").mtype(3).build(); + + final BidderCall httpCall = givenHttpCall(givenBidResponse(bannerBid, audioBid)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).containsExactly( + BidderError.badServerResponse("failed to parse bid mtype (3) for impression id \"id\"")); + assertThat(result.getValue()).containsOnly(BidderBid.of(bannerBid, banner, "USD")); + } + + @Test + public void makeBidsShouldReturnErrorWhenMtypeIsMissing() throws JsonProcessingException { + // given + final Bid bid = Bid.builder().id("bidId").impid("1").build(); + + final BidderCall httpCall = givenHttpCall(givenBidResponse(bid)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).containsExactly( + BidderError.badServerResponse("Missing MType for bid: bidId")); + } + + private static BidRequest givenBidRequest(UnaryOperator... impCustomizers) { + return BidRequest.builder() + .imp(Arrays.stream(impCustomizers).map(SevioBidderTest::givenImp).toList()) + .build(); + } + + private static Imp givenImp(UnaryOperator impCustomizer) { + return impCustomizer.apply(Imp.builder().id("impId")).build(); + } + + private static String givenBidResponse(Bid... bids) throws JsonProcessingException { + return mapper.writeValueAsString(BidResponse.builder() + .cur("USD") + .seatbid(singletonList(SeatBid.builder().bid(List.of(bids)).build())) + .build()); + } + + private static BidderCall givenHttpCall(String body) { + return BidderCall.succeededHttp( + HttpRequest.builder().build(), + HttpResponse.of(200, null, body), + null); + } +} diff --git a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughBidderTest.java b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughBidderTest.java index de04ce71e1f..189441fd7b8 100644 --- a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughBidderTest.java @@ -274,14 +274,14 @@ public void makeHttpRequestsShouldSplitImpressionsByMediaType() { assertThat(httpRequests) .extracting(HttpRequest::getPayload) .extracting(BidRequest::getImp) - .extracting(impressions -> impressions.getFirst()) + .extracting(List::getFirst) .allSatisfy(impression -> assertThat(impression.getId()).isEqualTo("123")); // The multiformat bid request is split into a bid request per media type assertThat(httpRequests) .extracting(HttpRequest::getPayload) .extracting(BidRequest::getImp) - .extracting(impressions -> impressions.getFirst()) + .extracting(List::getFirst) // Ignore audio impressions because it is currently not supported .satisfiesExactlyInAnyOrder( impression -> { @@ -450,8 +450,8 @@ private static BidRequest givenBidRequest( UnaryOperator bidRequestCustomizer, UnaryOperator impCustomizer) { - return bidRequestCustomizer.apply(BidRequest.builder() - .imp(singletonList(givenImp(impCustomizer)))) + return bidRequestCustomizer.apply( + BidRequest.builder().imp(singletonList(givenImp(impCustomizer)))) .build(); } @@ -460,13 +460,14 @@ private static BidRequest givenBidRequest(UnaryOperator impCusto } private static Imp givenImp(UnaryOperator impCustomizer) { - return impCustomizer.apply(Imp.builder() - .id("123") - .banner(Banner.builder().build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpSharethrough.of( - "pkey", - singletonList("imp.ext.badv"), - singletonList("imp.ext.bcat")))))) + return impCustomizer.apply( + Imp.builder() + .id("123") + .banner(Banner.builder().build()) + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpSharethrough.of( + "pkey", + singletonList("imp.ext.badv"), + singletonList("imp.ext.bcat")))))) .build(); } @@ -490,8 +491,8 @@ private static List givenSeatBid(Bid... bids) { private static Bid givenBid(String impid, BidType bidType, UnaryOperator bidCustomizer) { return bidCustomizer.apply(Bid.builder() - .impid(impid) - .ext(mapper.valueToTree(ExtPrebid.of(ExtBidPrebid.builder().type(bidType).build(), null)))) + .impid(impid) + .ext(mapper.valueToTree(ExtPrebid.of(ExtBidPrebid.builder().type(bidType).build(), null)))) .build(); } diff --git a/src/test/java/org/prebid/server/bidder/showheroes/ShowheroesBidderTest.java b/src/test/java/org/prebid/server/bidder/showheroes/ShowheroesBidderTest.java index acb15b91bb5..0e526a8059e 100644 --- a/src/test/java/org/prebid/server/bidder/showheroes/ShowheroesBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/showheroes/ShowheroesBidderTest.java @@ -30,18 +30,18 @@ import java.util.List; import java.util.function.Function; +import static java.util.Collections.singletonList; +import static java.util.function.Function.identity; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; import static org.mockito.Mock.Strictness.LENIENT; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import static org.mockito.BDDMockito.given; -import static java.util.Collections.singletonList; -import static java.util.function.Function.identity; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.tuple; import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; import static org.prebid.server.proto.openrtb.ext.response.BidType.video; import static org.prebid.server.util.HttpUtil.ACCEPT_HEADER; @@ -80,8 +80,8 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { final BidRequest bidRequest = BidRequest.builder() .site(Site.builder().page("https://test-example.com").build()) .imp(singletonList(Imp.builder() - .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))) - .build())) + .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))) + .build())) .build(); // when @@ -89,7 +89,7 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { // then assertThat(result.getErrors()).hasSize(1); - assertThat(result.getErrors().get(0).getMessage()).startsWith("Cannot deserialize value"); + assertThat(result.getErrors().getFirst().getMessage()).startsWith("Cannot deserialize value"); assertThat(result.getValue()).isEmpty(); } @@ -106,7 +106,7 @@ public void makeHttpRequestsShouldReturnErrorWhenSitePageIsEmpty() { // then assertThat(result.getErrors()).hasSize(1); - assertThat(result.getErrors().get(0).getMessage()).isEqualTo("BidRequest.site.page is required"); + assertThat(result.getErrors().getFirst().getMessage()).isEqualTo("BidRequest.site.page is required"); assertThat(result.getValue()).isEmpty(); } @@ -123,7 +123,7 @@ public void makeHttpRequestsShouldReturnErrorWhenAppBundleIsEmpty() { // then assertThat(result.getErrors()).hasSize(1); - assertThat(result.getErrors().get(0).getMessage()).isEqualTo("BidRequest.app.bundle is required"); + assertThat(result.getErrors().getFirst().getMessage()).isEqualTo("BidRequest.app.bundle is required"); assertThat(result.getValue()).isEmpty(); } @@ -138,7 +138,7 @@ public void makeHttpRequestsShouldCreateCorrectURL() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - assertThat(result.getValue().get(0).getUri()).isEqualTo(ENDPOINT_URL); + assertThat(result.getValue().getFirst().getUri()).isEqualTo(ENDPOINT_URL); } @Test diff --git a/src/test/java/org/prebid/server/bidder/smartrtb/SmartrtbBidderTest.java b/src/test/java/org/prebid/server/bidder/smartrtb/SmartrtbBidderTest.java index 9f9f8110cae..8c700b96bb3 100644 --- a/src/test/java/org/prebid/server/bidder/smartrtb/SmartrtbBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/smartrtb/SmartrtbBidderTest.java @@ -121,7 +121,7 @@ public void makeHttpRequestsShouldSetExpectedRequestUrlAndDefaultHeaders() { @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given - final BidderCall httpCall = givenHttpCall(null, "false"); + final BidderCall httpCall = givenHttpCall("false"); // when final Result> result = target.makeBids(httpCall, null); @@ -135,7 +135,6 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { public void makeBidsShouldReturnErrorWhenBidExtIsEmpty() throws JsonProcessingException { // given final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); // when final Result> result = target.makeBids(httpCall, null); @@ -151,7 +150,6 @@ public void makeBidsShouldReturnTypeBannerWhenResponseExtCreativeTypeIsBanner() // given final ObjectNode ext = mapper.valueToTree(SmartrtbResponseExt.of("BANNER")); final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(ext)))); // when @@ -167,7 +165,6 @@ public void makeBidsShouldReturnTypeBannerWhenResponseExtCreativeTypeEmpty() thr // given final ObjectNode ext = mapper.valueToTree(SmartrtbResponseExt.of("wrong type")); final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(ext)))); // when @@ -207,9 +204,9 @@ private static BidResponse givenBidResponse(Function givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), + HttpRequest.builder().payload(null).build(), HttpResponse.of(200, null, body), null); } diff --git a/src/test/java/org/prebid/server/bidder/sonobi/SonobiBidderTest.java b/src/test/java/org/prebid/server/bidder/sonobi/SonobiBidderTest.java index d5152ee00cc..40dd077fead 100644 --- a/src/test/java/org/prebid/server/bidder/sonobi/SonobiBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/sonobi/SonobiBidderTest.java @@ -309,9 +309,10 @@ private static BidRequest givenBidRequest( Function impCustomizer, Function requestCustomizer) { - return requestCustomizer.apply(BidRequest.builder() - .cur(singletonList("USD")) - .imp(singletonList(givenImp(impCustomizer)))) + return requestCustomizer.apply( + BidRequest.builder() + .cur(singletonList("USD")) + .imp(singletonList(givenImp(impCustomizer)))) .build(); } diff --git a/src/test/java/org/prebid/server/bidder/sovrnxsp/SovrnXspBidderTest.java b/src/test/java/org/prebid/server/bidder/sovrnxsp/SovrnXspBidderTest.java index 8ff6e27fae1..c2032721617 100644 --- a/src/test/java/org/prebid/server/bidder/sovrnxsp/SovrnXspBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/sovrnxsp/SovrnXspBidderTest.java @@ -399,10 +399,11 @@ private static BidRequest givenBidRequest(UnaryOperator... impCu } private static Imp givenImp(UnaryOperator impCustomizer) { - return impCustomizer.apply(Imp.builder() - .id("imp_id") - .banner(Banner.builder().build()) - .ext(givenImpExt(identity()))) + return impCustomizer.apply( + Imp.builder() + .id("imp_id") + .banner(Banner.builder().build()) + .ext(givenImpExt(identity()))) .build(); } diff --git a/src/test/java/org/prebid/server/bidder/sparteo/SparteoBidderTest.java b/src/test/java/org/prebid/server/bidder/sparteo/SparteoBidderTest.java index e741c5e29c6..8b973b775f1 100644 --- a/src/test/java/org/prebid/server/bidder/sparteo/SparteoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/sparteo/SparteoBidderTest.java @@ -21,6 +21,7 @@ import org.prebid.server.bidder.model.HttpRequest; import org.prebid.server.bidder.model.HttpResponse; import org.prebid.server.bidder.model.Result; +import org.prebid.server.proto.openrtb.ext.FlexibleExtension; import org.prebid.server.proto.openrtb.ext.request.ExtPublisher; import org.prebid.server.proto.openrtb.ext.response.BidType; @@ -190,7 +191,7 @@ public void makeHttpRequestsShouldHandleRequestWithoutSiteOrPublisher() { } @Test - public void makeHttpRequestsShouldMergeNetworkIdIntoExistingPublisherExtParams() throws JsonProcessingException { + public void makeHttpRequestsShouldMergeNetworkIdIntoExistingPublisherExtParams() { // given final ObjectNode impExt = mapper.createObjectNode(); impExt.set("bidder", mapper.createObjectNode().put("networkId", "testNetworkId")); @@ -222,8 +223,7 @@ public void makeHttpRequestsShouldMergeNetworkIdIntoExistingPublisherExtParams() } @Test - public void makeHttpRequestsShouldAddParamsToPublisherExtWhenExtExistsWithoutParams() - throws JsonProcessingException { + public void makeHttpRequestsShouldAddParamsToPublisherExtWhenExtExistsWithoutParams() { // given final ObjectNode impExt = mapper.createObjectNode(); impExt.set("bidder", mapper.createObjectNode().put("networkId", "testNetworkId")); @@ -247,7 +247,7 @@ public void makeHttpRequestsShouldAddParamsToPublisherExtWhenExtExistsWithoutPar .extracting(BidRequest::getSite) .extracting(Site::getPublisher) .extracting(Publisher::getExt) - .extracting(ext -> ext.getProperties()) + .extracting(FlexibleExtension::getProperties) .allSatisfy(properties -> { assertThat(properties.get("params").get("networkId").asText()).isEqualTo("testNetworkId"); assertThat(properties.get("otherField").asText()).isEqualTo("otherValue"); @@ -275,9 +275,9 @@ public void makeHttpRequestsShouldAppendSiteDomainAndNetworkIdAsQueryParams() { final BidRequest bidRequest = givenBidRequest( r -> r.site(Site.builder() - .domain("dev.sparteo.com") - .publisher(Publisher.builder().build()) - .build()), + .domain("dev.sparteo.com") + .publisher(Publisher.builder().build()) + .build()), givenImp(i -> i.ext(impExt))); // when @@ -299,10 +299,10 @@ public void makeHttpRequestsShouldAppendSitePageDomainAndNetworkIdAsQueryParams( final BidRequest bidRequest = givenBidRequest( r -> r.site(Site.builder() - .domain(null) - .page("https://www.dev.sparteo.com:3000/p") - .publisher(Publisher.builder().build()) - .build()), + .domain(null) + .page("https://www.dev.sparteo.com:3000/p") + .publisher(Publisher.builder().build()) + .build()), givenImp(i -> i.ext(impExt))); // when @@ -323,9 +323,9 @@ public void makeHttpRequestsShouldUseSiteDomainWhenPublisherDomainIsMissing() { final BidRequest bidRequest = givenBidRequest( r -> r.site(Site.builder() - .domain("dev.sparteo.com") - .publisher(Publisher.builder().build()) - .build()), + .domain("dev.sparteo.com") + .publisher(Publisher.builder().build()) + .build()), givenImp(i -> i.ext(impExt))); // when @@ -346,9 +346,9 @@ public void makeHttpRequestsShouldPreferSiteDomainOverPublisherDomain() { final BidRequest bidRequest = givenBidRequest( r -> r.site(Site.builder() - .domain("site.sparteo.com") - .publisher(Publisher.builder().domain("dev.sparteo.com").build()) - .build()), + .domain("site.sparteo.com") + .publisher(Publisher.builder().domain("dev.sparteo.com").build()) + .build()), givenImp(i -> i.ext(impExt))); // when @@ -406,7 +406,7 @@ public void makeHttpRequestsShouldSetNetworkIdOnAppPublisherExtWhenNoSite() { // then assertMissingBundleWarning(result); - final BidRequest out = result.getValue().get(0).getPayload(); + final BidRequest out = result.getValue().getFirst().getPayload(); assertThat(out.getApp()).isNotNull(); assertThat(out.getApp().getPublisher()).isNotNull(); @@ -436,7 +436,7 @@ public void makeHttpRequestsShouldCreateAppPublisherWhenMissingAndSetNetworkId() // then assertMissingBundleWarning(result); - final BidRequest out = result.getValue().get(0).getPayload(); + final BidRequest out = result.getValue().getFirst().getPayload(); assertThat(out.getApp()).isNotNull(); assertThat(out.getApp().getPublisher()).isNotNull(); @@ -577,11 +577,11 @@ public void makeHttpRequestsShouldWarnAndSetUnknownAppDomainWhenAppDomainMissing final BidRequest bidRequest = givenBidRequest( r -> r.site(null) - .app(App.builder() - .domain(null) - .bundle("com.example.bundle") - .publisher(Publisher.builder().build()) - .build()), + .app(App.builder() + .domain(null) + .bundle("com.example.bundle") + .publisher(Publisher.builder().build()) + .build()), givenImp(i -> i.ext(impExt))); // when @@ -657,7 +657,7 @@ public void makeBidsShouldReturnErrorWhenResponseBodyIsInvalidJson() { } @Test - public void makeBidsShouldReturnEmptyResultWhenBidResponseIsNull() throws JsonProcessingException { + public void makeBidsShouldReturnEmptyResultWhenBidResponseIsNull() { // given final BidderCall httpCall = BidderCall.succeededHttp( HttpRequest.builder().payload(givenBidRequest()).build(), @@ -673,7 +673,7 @@ public void makeBidsShouldReturnEmptyResultWhenBidResponseIsNull() throws JsonPr } @Test - public void makeBidsShouldReturnEmptyResultWhenBidResponseHasNoSeatBids() throws JsonProcessingException { + public void makeBidsShouldReturnEmptyResultWhenBidResponseHasNoSeatBids() { // given final BidResponse bidResponse = BidResponse.builder().seatbid(Collections.emptyList()).build(); final BidderCall httpCall = givenHttpCall(givenBidRequest(), bidResponse); @@ -687,7 +687,7 @@ public void makeBidsShouldReturnEmptyResultWhenBidResponseHasNoSeatBids() throws } @Test - public void makeBidsShouldReturnBannerBidWhenMediaTypeIsBanner() throws JsonProcessingException { + public void makeBidsShouldReturnBannerBidWhenMediaTypeIsBanner() { // given final Bid bid = givenBid(builder -> builder.impid("imp1").price(BigDecimal.valueOf(1.23)).adm("adm-banner"), BidType.banner.getName()); @@ -704,7 +704,7 @@ public void makeBidsShouldReturnBannerBidWhenMediaTypeIsBanner() throws JsonProc } @Test - public void makeBidsShouldReturnVideoBidWhenMediaTypeIsVideo() throws JsonProcessingException { + public void makeBidsShouldReturnVideoBidWhenMediaTypeIsVideo() { // given final Bid bid = givenBid(builder -> builder.impid("imp2").price(BigDecimal.valueOf(2.34)).adm("adm-video"), @@ -722,7 +722,7 @@ public void makeBidsShouldReturnVideoBidWhenMediaTypeIsVideo() throws JsonProces } @Test - public void makeBidsShouldReturnNativeBidWhenMediaTypeIsNative() throws JsonProcessingException { + public void makeBidsShouldReturnNativeBidWhenMediaTypeIsNative() { // given final Bid bid = givenBid(builder -> builder.impid("imp3").price(BigDecimal.valueOf(3.45)).adm("adm-native"), @@ -740,13 +740,13 @@ public void makeBidsShouldReturnNativeBidWhenMediaTypeIsNative() throws JsonProc } @Test - public void makeBidsShouldReturnErrorForUnsupportedMediaTypeAndProcessOthers() throws JsonProcessingException { + public void makeBidsShouldReturnErrorForUnsupportedMediaTypeAndProcessOthers() { // given final Bid audioBid = givenBid(builder -> - builder.impid("impAudio").price(BigDecimal.ONE), + builder.impid("impAudio").price(BigDecimal.ONE), BidType.audio.getName()); final Bid bannerBid = givenBid(builder -> - builder.impid("impBanner").price(BigDecimal.valueOf(2.0)), + builder.impid("impBanner").price(BigDecimal.valueOf(2.0)), BidType.banner.getName()); final BidResponse bidResponse = givenBidResponse(List.of(audioBid, bannerBid), "EUR"); final BidderCall httpCall = givenHttpCall(givenBidRequest(), bidResponse); @@ -765,7 +765,7 @@ public void makeBidsShouldReturnErrorForUnsupportedMediaTypeAndProcessOthers() t } @Test - public void makeBidsShouldReturnErrorWhenBidExtIsNull() throws JsonProcessingException { + public void makeBidsShouldReturnErrorWhenBidExtIsNull() { // given final Bid bid = givenBid(builder -> builder.impid("imp1").ext(null), null); final BidResponse bidResponse = givenBidResponse(bid, "USD"); @@ -782,7 +782,7 @@ public void makeBidsShouldReturnErrorWhenBidExtIsNull() throws JsonProcessingExc } @Test - public void makeBidsShouldReturnErrorWhenPrebidIsMissingInBidExt() throws JsonProcessingException { + public void makeBidsShouldReturnErrorWhenPrebidIsMissingInBidExt() { // given final Bid bid = givenBid(builder -> builder.impid("imp1").ext(mapper.createObjectNode()), null); final BidResponse bidResponse = givenBidResponse(bid, "USD"); @@ -799,7 +799,7 @@ public void makeBidsShouldReturnErrorWhenPrebidIsMissingInBidExt() throws JsonPr } @Test - public void makeBidsShouldReturnErrorWhenPrebidTypeIsMissingInBidExt() throws JsonProcessingException { + public void makeBidsShouldReturnErrorWhenPrebidTypeIsMissingInBidExt() { // given final Bid bid = givenBid(builder -> builder.impid("imp1").ext(createBidExtWithEmptyPrebid()), null); final BidResponse bidResponse = givenBidResponse(bid, "USD"); @@ -816,7 +816,7 @@ public void makeBidsShouldReturnErrorWhenPrebidTypeIsMissingInBidExt() throws Js } @Test - public void makeBidsShouldReturnErrorWhenPrebidCannotBeParsed() throws JsonProcessingException { + public void makeBidsShouldReturnErrorWhenPrebidCannotBeParsed() { // given final ObjectNode malformedExt = mapper.createObjectNode(); malformedExt.putArray("prebid"); @@ -835,7 +835,7 @@ public void makeBidsShouldReturnErrorWhenPrebidCannotBeParsed() throws JsonProce } @Test - public void makeBidsShouldReturnErrorWhenPrebidTypeIsUnsupported() throws JsonProcessingException { + public void makeBidsShouldReturnErrorWhenPrebidTypeIsUnsupported() { // given final Bid bid = givenBid(builder -> builder.impid("imp1"), "unknown-type"); final BidResponse bidResponse = givenBidResponse(bid, "USD"); @@ -852,7 +852,7 @@ public void makeBidsShouldReturnErrorWhenPrebidTypeIsUnsupported() throws JsonPr } @Test - public void makeBidsShouldProcessValidBidsWhenSeatBidContainsNulls() throws JsonProcessingException { + public void makeBidsShouldProcessValidBidsWhenSeatBidContainsNulls() { // given final Bid validBid = givenBid(builder -> builder.impid("validImp").price(BigDecimal.ONE), @@ -875,7 +875,7 @@ public void makeBidsShouldProcessValidBidsWhenSeatBidContainsNulls() throws Json } @Test - public void makeBidsShouldCorrectlyProcessMultipleBidsAndSeatBids() throws JsonProcessingException { + public void makeBidsShouldCorrectlyProcessMultipleBidsAndSeatBids() { // given final Bid bid1 = givenBid(builder -> builder.impid("imp1").price(BigDecimal.valueOf(1.0)), @@ -908,7 +908,7 @@ public void makeBidsShouldCorrectlyProcessMultipleBidsAndSeatBids() throws JsonP } @Test - public void makeBidsShouldReturnErrorWhenPrebidExtIsNullNode() throws JsonProcessingException { + public void makeBidsShouldReturnErrorWhenPrebidExtIsNullNode() { // given final ObjectNode bidExtWithNullPrebid = mapper.createObjectNode(); bidExtWithNullPrebid.set("prebid", NullNode.getInstance()); @@ -928,7 +928,7 @@ public void makeBidsShouldReturnErrorWhenPrebidExtIsNullNode() throws JsonProces } @Test - public void makeBidsShouldProcessValidSeatBidsWhenResponseContainsNulls() throws JsonProcessingException { + public void makeBidsShouldProcessValidSeatBidsWhenResponseContainsNulls() { // given final Bid validBid1 = givenBid(builder -> builder.impid("validImp1").price(BigDecimal.TEN), @@ -960,7 +960,7 @@ public void makeBidsShouldProcessValidSeatBidsWhenResponseContainsNulls() throws } @Test - public void makeBidsShouldReturnEmptyResultWhenSeatBidHasNullBidList() throws JsonProcessingException { + public void makeBidsShouldReturnEmptyResultWhenSeatBidHasNullBidList() { // given final SeatBid seatBidWithNullBids = SeatBid.builder().bid(null).build(); final BidResponse bidResponse = @@ -976,7 +976,7 @@ public void makeBidsShouldReturnEmptyResultWhenSeatBidHasNullBidList() throws Js } @Test - public void makeBidsShouldReturnEmptyResultWhenSeatBidHasEmptyBidList() throws JsonProcessingException { + public void makeBidsShouldReturnEmptyResultWhenSeatBidHasEmptyBidList() { // given final SeatBid seatBidWithEmptyBids = SeatBid.builder().bid(Collections.emptyList()).build(); final BidResponse bidResponse = diff --git a/src/test/java/org/prebid/server/bidder/startio/StartioBidderTest.java b/src/test/java/org/prebid/server/bidder/startio/StartioBidderTest.java index 31a7c4ce91f..85385da341c 100644 --- a/src/test/java/org/prebid/server/bidder/startio/StartioBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/startio/StartioBidderTest.java @@ -203,7 +203,7 @@ public void makeHttpRequestsShouldSplitRequestByImpressions() { @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given - final BidderCall httpCall = givenHttpCall(null, "invalid"); + final BidderCall httpCall = givenHttpCall("invalid"); // when final Result> result = target.makeBids(httpCall, null); @@ -220,7 +220,7 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { @Test public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(null)); + final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(null)); // when final Result> result = target.makeBids(httpCall, null); @@ -233,7 +233,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProces @Test public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( mapper.writeValueAsString(BidResponse.builder().build())); // when @@ -247,7 +247,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws Jso @Test public void makeBidsShouldReportErrorAndSkipBidIfCannotParseBidType() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, + final BidderCall httpCall = givenHttpCall( givenBidResponse( givenBid("001", BidType.banner), givenBid("002", BidType.video), @@ -289,16 +289,16 @@ private static Imp givenImp(UnaryOperator impCustomizer) { return impCustomizer.apply(Imp.builder().id("345").banner(Banner.builder().build())).build(); } - private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), + HttpRequest.builder().payload(null).build(), HttpResponse.of(200, null, body), null); } - private BidderCall givenHttpCall(BidRequest bidRequest, BidResponse bidResponse) + private BidderCall givenHttpCall(BidResponse bidResponse) throws JsonProcessingException { - return givenHttpCall(bidRequest, mapper.writeValueAsString(bidResponse)); + return givenHttpCall(mapper.writeValueAsString(bidResponse)); } private static BidResponse givenBidResponse(Bid... bids) { diff --git a/src/test/java/org/prebid/server/bidder/synapsehx/SynapseHXBidderTest.java b/src/test/java/org/prebid/server/bidder/synapsehx/SynapseHXBidderTest.java new file mode 100644 index 00000000000..250d17b9905 --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/synapsehx/SynapseHXBidderTest.java @@ -0,0 +1,261 @@ +package org.prebid.server.bidder.synapsehx; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.vertx.core.MultiMap; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderCall; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.HttpResponse; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.synapsehx.ExtImpSynapseHX; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.HttpUtil; + +import java.util.List; +import java.util.Map; +import java.util.function.UnaryOperator; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static java.util.function.UnaryOperator.identity; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.tuple; + +public class SynapseHXBidderTest extends VertxTest { + + private SynapseHXBidder target; + + @BeforeEach + public void setUp() { + target = new SynapseHXBidder("http://test.endpoint.com", jacksonMapper); + } + + @Test + public void creationShouldFailOnInvalidEndpointUrl() { + assertThatIllegalArgumentException().isThrownBy( + () -> new SynapseHXBidder("invalid_url", jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldCorrectlyAddHeaders() { + // given + final BidRequest bidRequest = givenBidRequest(identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()) + .extracting(HttpRequest::getHeaders) + .flatExtracting(MultiMap::entries) + .extracting(Map.Entry::getKey, Map.Entry::getValue) + .containsExactlyInAnyOrder( + tuple(HttpUtil.CONTENT_TYPE_HEADER.toString(), HttpUtil.APPLICATION_JSON_CONTENT_TYPE), + tuple(HttpUtil.ACCEPT_HEADER.toString(), HttpHeaderValues.APPLICATION_JSON.toString()), + tuple(HttpUtil.X_OPENRTB_VERSION_HEADER.toString(), "2.6")); + } + + @Test + public void makeHttpRequestsShouldReturnErrorWhenImpressionContainsInvalidBidderParameters() { + // given + final ObjectNode invalidExt = mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode())); + + final BidRequest bidRequest = givenBidRequest(identity(), + impBuilder -> impBuilder.id("Imp01").ext(invalidExt)); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).satisfiesExactly( + error -> assertThat(error.getMessage()).startsWith("Failed to parse bidder parameters")); + } + + @Test + public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { + // given + final BidderCall httpCall = givenHttpCall("invalid"); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response); + assertThat(error.getMessage()).startsWith("Failed to decode: Unrecognized token"); + }); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(null)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall( + mapper.writeValueAsString(BidResponse.builder().build())); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldSkipBidWithUnsupportedBidTypeAndKeepValidBid() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall( + givenBidResponse( + givenBidWithMType("Imp1", BidType.banner), + givenBidWithMType("Imp2", BidType.audio))); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).satisfiesExactly( + error -> assertThat(error.getMessage()).startsWith("Unsupported media type")); + assertThat(result.getValue()).satisfiesExactly( + bid -> assertThat(bid.getBid().getImpid()).isEqualTo("Imp1")); + } + + @Test + public void makeBidsShouldReportErrorsSkipForBidsWithUnsupportedOrMissingBidType() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall( + givenBidResponse( + givenBidWithMType("Imp1", BidType.xNative), + givenBidWithMType("Imp2", BidType.audio), + givenBid("Imp3", BidType.xNative), + givenBid("Imp4", BidType.audio), + givenBid("Imp9", BidType.banner).toBuilder().ext(null).build())); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).hasSize(5).allSatisfy( + error -> assertThat(error.getMessage()).startsWith("Unsupported media type")); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsCorrectlyRecogniseBidTypeWithFallback() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall( + givenBidResponse( + givenBidWithMType("Imp1", BidType.banner), + givenBidWithMType("Imp2", BidType.video), + givenBid("Imp3", BidType.banner), + givenBid("Imp4", BidType.video))); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).satisfiesExactlyInAnyOrder( + bid -> { + assertThat(bid.getBid().getImpid()).isEqualTo("Imp1"); + assertThat(bid.getType()).isEqualTo(BidType.banner); + }, + bid -> { + assertThat(bid.getBid().getImpid()).isEqualTo("Imp2"); + assertThat(bid.getType()).isEqualTo(BidType.video); + }, + bid -> { + assertThat(bid.getBid().getImpid()).isEqualTo("Imp3"); + assertThat(bid.getType()).isEqualTo(BidType.banner); + }, + bid -> { + assertThat(bid.getBid().getImpid()).isEqualTo("Imp4"); + assertThat(bid.getType()).isEqualTo(BidType.video); + } + ); + } + + private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { + return givenBidRequest(identity(), impCustomizer); + } + + private static BidRequest givenBidRequest( + UnaryOperator bidRequestCustomizer, + UnaryOperator impCustomizer) { + + return bidRequestCustomizer.apply(BidRequest.builder() + .imp(singletonList(givenImp(impCustomizer)))) + .build(); + } + + private static Imp givenImp(UnaryOperator impCustomizer) { + return givenImp(impCustomizer, ExtImpSynapseHX.of("tenant-id")); + } + + private static Imp givenImp(UnaryOperator impCustomizer, ExtImpSynapseHX extImp) { + return impCustomizer.apply(Imp.builder() + .id("345") + .banner(Banner.builder().build()) + .ext(mapper.valueToTree(ExtPrebid.of(null, extImp)))) + .build(); + } + + private static BidderCall givenHttpCall(String body) { + return BidderCall.succeededHttp( + HttpRequest.builder().payload(null).build(), + HttpResponse.of(200, null, body), + null); + } + + private BidderCall givenHttpCall(BidResponse bidResponse) + throws JsonProcessingException { + return givenHttpCall(mapper.writeValueAsString(bidResponse)); + } + + private static BidResponse givenBidResponse(Bid... bids) { + return BidResponse.builder().seatbid(singletonList( + SeatBid.builder().bid(asList(bids)).build())).build(); + } + + private static Bid givenBid(String impid, BidType bidType) { + return Bid.builder() + .impid(impid) + .ext(mapper.createObjectNode() + .set("prebid", mapper.createObjectNode() + .put("type", bidType.getName()))) + .build(); + } + + private static Bid givenBidWithMType(String impid, BidType bidType) { + return Bid.builder().impid(impid).mtype(bidType.ordinal() + 1).build(); + } + +} diff --git a/src/test/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidderTest.java b/src/test/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidderTest.java index 46db30df08c..06e6c25817a 100644 --- a/src/test/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidderTest.java @@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.tuple; +import static org.prebid.server.proto.openrtb.ext.response.BidType.audio; import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; import static org.prebid.server.proto.openrtb.ext.response.BidType.video; import static org.prebid.server.proto.openrtb.ext.response.BidType.xNative; @@ -429,6 +430,21 @@ public void makeBidsShouldReturnxNativeBid() throws JsonProcessingException { .containsExactly(BidderBid.of(Bid.builder().impid("123").mtype(4).build(), xNative, "USD")); } + @Test + public void makeBidsShouldReturnAudioBid() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall( + givenBidResponse(bidBuilder -> bidBuilder.mtype(3).impid("123"))); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .containsExactly(BidderBid.of(Bid.builder().impid("123").mtype(3).build(), audio, "USD")); + } + @Test public void makeBidsShouldReturnBannerBid() throws JsonProcessingException { // given @@ -483,7 +499,7 @@ public void makeBidsShouldReturnValidBidsAndErrorsForMixedMediaTypes() throws Js .seatbid(singletonList(SeatBid.builder() .bid(Arrays.asList( Bid.builder().mtype(1).impid("valid1").build(), // valid banner - Bid.builder().mtype(3).impid("invalid1").build(), // invalid mtype + Bid.builder().mtype(5).impid("invalid1").build(), // invalid mtype Bid.builder().mtype(2).impid("valid2").build(), // valid video Bid.builder().mtype(null).impid("invalid2").build() // null mtype )) diff --git a/src/test/java/org/prebid/server/bidder/tpmn/TpmnBidderTest.java b/src/test/java/org/prebid/server/bidder/tpmn/TpmnBidderTest.java index 81eb7599f80..7664e90a9d4 100644 --- a/src/test/java/org/prebid/server/bidder/tpmn/TpmnBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/tpmn/TpmnBidderTest.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.node.TextNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; import com.iab.openrtb.response.Bid; @@ -250,11 +249,10 @@ private BidRequest givenBidRequest(UnaryOperator... impCustomize } private Imp givenImp(UnaryOperator impCustomizer) { - return impCustomizer.apply( - Imp.builder().ext(givenImpExt("publisher_id", "ad_unit_id"))).build(); + return impCustomizer.apply(Imp.builder().ext(givenImpExt())).build(); } - private ObjectNode givenImpExt(String publisherId, String adUnitId) { + private ObjectNode givenImpExt() { return mapper.valueToTree( ExtPrebid.of(null, mapper.createObjectNode())); } @@ -268,15 +266,6 @@ private static BidResponse givenBidResponse(Bid... bids) { .build(); } - private static ObjectNode givenBidExt(String value) { - return mapper.createObjectNode() - .set("prebid", mapper.createObjectNode().set("type", TextNode.valueOf(value))); - } - - private static Bid givenBid(String type) { - return Bid.builder().impid("123").ext(givenBidExt(type)).build(); - } - private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { return BidderCall.succeededHttp( HttpRequest.builder().payload(bidRequest).build(), diff --git a/src/test/java/org/prebid/server/bidder/triplelift/TripleliftBidderTest.java b/src/test/java/org/prebid/server/bidder/triplelift/TripleliftBidderTest.java index 4fd65923014..f30f50671b2 100644 --- a/src/test/java/org/prebid/server/bidder/triplelift/TripleliftBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/triplelift/TripleliftBidderTest.java @@ -134,7 +134,7 @@ public void makeHttpRequestsShouldModifyBidFloorFromImpExtWhenFloorIsPresent() { @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given - final BidderCall httpCall = givenHttpCall(null, "invalid"); + final BidderCall httpCall = givenHttpCall("invalid"); // when final Result> result = target.makeBids(httpCall, null); @@ -149,7 +149,7 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { @Test public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(null)); + final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(null)); // when final Result> result = target.makeBids(httpCall, null); @@ -163,7 +163,6 @@ public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProces public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { // given final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(BidResponse.builder().build())); // when @@ -178,7 +177,6 @@ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws Jso public void makeBidsShouldReturnErrorWhenBidExtIsEmpty() throws JsonProcessingException { // given final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); // when @@ -196,7 +194,6 @@ public void makeBidsShouldReturnTypeBannerWhenTripleliftResponseExtIsEmpty() thr // given final ObjectNode ext = mapper.valueToTree(TripleliftResponseExt.of(null)); final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(ext)))); // when @@ -213,7 +210,6 @@ public void makeBidsShouldReturnTypeBannerWhenTripleliftInnerExtIsNull() throws // given final ObjectNode ext = mapper.valueToTree(TripleliftResponseExt.of(TripleliftInnerExt.of(null))); final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(ext)))); // when @@ -230,7 +226,6 @@ public void makeBidsShouldReturnTypeBannerWhenTripleliftInnerExtIsNotEleven() th // given final ObjectNode ext = mapper.valueToTree(TripleliftResponseExt.of(TripleliftInnerExt.of(0))); final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(ext)))); // when @@ -247,7 +242,6 @@ public void makeBidsShouldReturnTypeVideoWhenTripleliftInnerExtIsEleven() throws // given final ObjectNode ext = mapper.valueToTree(TripleliftResponseExt.of(TripleliftInnerExt.of(11))); final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(ext)))); // when @@ -264,7 +258,6 @@ public void makeBidsShouldReturnTypeVideoWhenTripleliftInnerExtIsTwelve() throws // given final ObjectNode ext = mapper.valueToTree(TripleliftResponseExt.of(TripleliftInnerExt.of(12))); final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(ext)))); // when @@ -281,7 +274,6 @@ public void makeBidsShouldReturnTypeVideoWhenTripleliftInnerExtIsSeventeen() thr // given final ObjectNode ext = mapper.valueToTree(TripleliftResponseExt.of(TripleliftInnerExt.of(17))); final BidderCall httpCall = givenHttpCall( - null, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(ext)))); // when @@ -302,9 +294,9 @@ private static BidResponse givenBidResponse(Function givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), + HttpRequest.builder().payload(null).build(), HttpResponse.of(200, null, body), null); } diff --git a/src/test/java/org/prebid/server/bidder/tripleliftnative/TripleliftNativeBidderTest.java b/src/test/java/org/prebid/server/bidder/tripleliftnative/TripleliftNativeBidderTest.java index ea8fae6c12b..f490b1a091a 100644 --- a/src/test/java/org/prebid/server/bidder/tripleliftnative/TripleliftNativeBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/tripleliftnative/TripleliftNativeBidderTest.java @@ -120,8 +120,7 @@ public void makeHttpRequestsShouldReturnErrorsWhenNoPublisherIdIsSpecified() { final BidRequest bidRequest = givenBidRequest( impBuilder -> impBuilder.xNative(Native.builder().build()), - ExtImpTriplelift.of("inventoryCode", new BigDecimal(23)), - null); + ExtImpTriplelift.of("inventoryCode", new BigDecimal(23))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -358,10 +357,9 @@ private static BidRequest givenBidRequest( } private static BidRequest givenBidRequest(UnaryOperator impCustomizer, - ExtImpTriplelift extImpBidder, - TripleliftNativeExtImpData extImpData) { + ExtImpTriplelift extImpBidder) { - return givenBidRequest(identity(), impCustomizer, extImpBidder, extImpData); + return givenBidRequest(identity(), impCustomizer, extImpBidder, null); } private static Imp givenImp(UnaryOperator impCustomizer, diff --git a/src/test/java/org/prebid/server/bidder/unruly/UnrulyBidderTest.java b/src/test/java/org/prebid/server/bidder/unruly/UnrulyBidderTest.java index c059eb1f291..e9bafc5a305 100644 --- a/src/test/java/org/prebid/server/bidder/unruly/UnrulyBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/unruly/UnrulyBidderTest.java @@ -296,19 +296,6 @@ public void makeBidsShouldReturnErrorNotFoundBidRequest() throws JsonProcessingE .containsExactly(BidderBid.of(Bid.builder().impid("111").build(), banner, "USD")); } - private static BidRequest givenBidRequest( - Function bidRequestCustomizer, - Function impCustomizer) { - - return bidRequestCustomizer.apply(BidRequest.builder() - .imp(singletonList(givenImp(impCustomizer)))) - .build(); - } - - private static BidRequest givenBidRequest(Function impCustomizer) { - return givenBidRequest(identity(), impCustomizer); - } - private static Imp givenImp(Function impCustomizer) { final ObjectNode impExt = mapper.valueToTree( UnrulyExtPrebid.of(ExtImpUnruly.of(123), "gpid")); diff --git a/src/test/java/org/prebid/server/bidder/vox/VoxBidderTest.java b/src/test/java/org/prebid/server/bidder/vox/VoxBidderTest.java index 05a815c97bd..97af817fb87 100644 --- a/src/test/java/org/prebid/server/bidder/vox/VoxBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/vox/VoxBidderTest.java @@ -275,8 +275,11 @@ private static BidderCall givenHttpCall(BidRequest bidRequest, Strin @Value(staticConstructor = "of") private static class VoxImpExt { + String placementId; + String imageUrl; + Set displaySizes; } } diff --git a/src/test/java/org/prebid/server/bidder/yahooads/YahooAdsBidderTest.java b/src/test/java/org/prebid/server/bidder/yahooads/YahooAdsBidderTest.java index 7966a94e911..5abbb2dc509 100644 --- a/src/test/java/org/prebid/server/bidder/yahooads/YahooAdsBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/yahooads/YahooAdsBidderTest.java @@ -1,6 +1,8 @@ package org.prebid.server.bidder.yahooads; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.IntNode; +import com.fasterxml.jackson.databind.node.TextNode; import com.iab.openrtb.request.App; import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; @@ -16,11 +18,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.VertxTest; -import org.prebid.server.auction.versionconverter.BidRequestOrtbVersionConversionManager; -import org.prebid.server.auction.versionconverter.OrtbVersion; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; import org.prebid.server.bidder.model.BidderError; @@ -43,10 +42,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.tuple; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mock.Strictness.LENIENT; -import static org.mockito.Mockito.when; import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; import static org.prebid.server.proto.openrtb.ext.response.BidType.video; @@ -55,22 +50,16 @@ public class YahooAdsBidderTest extends VertxTest { private static final String ENDPOINT_URL = "https://test.endpoint.com"; - @Mock(strictness = LENIENT) - private BidRequestOrtbVersionConversionManager conversionManager; - private YahooAdsBidder target; @BeforeEach public void setUp() { - when(conversionManager.convertFromAuctionSupportedVersion(any(BidRequest.class), eq(OrtbVersion.ORTB_2_5))) - .thenAnswer(answer -> answer.getArgument(0)); - target = new YahooAdsBidder(ENDPOINT_URL, conversionManager, jacksonMapper); + target = new YahooAdsBidder(ENDPOINT_URL, jacksonMapper); } @Test public void creationShouldFailOnInvalidEndpointUrl() { - assertThatIllegalArgumentException().isThrownBy(() -> new YahooAdsBidder("invalid_url", - conversionManager, jacksonMapper)); + assertThatIllegalArgumentException().isThrownBy(() -> new YahooAdsBidder("invalid_url", jacksonMapper)); } @Test @@ -282,7 +271,7 @@ public void makeHttpRequestsShouldSetExpectedHeaders() { assertThat(result.getValue().getFirst().getHeaders()) .extracting(Map.Entry::getKey, Map.Entry::getValue) .containsOnly(tuple("User-Agent", "UA"), - tuple("x-openrtb-version", "2.5"), + tuple("x-openrtb-version", "2.6"), tuple("Content-Type", "application/json;charset=utf-8"), tuple("Accept", "application/json")); } @@ -402,57 +391,542 @@ public void makeBidsShouldSkipNotSupportedImpAndReturnVideoBidWhenVideoPresent() } @Test - public void makeBidsShouldRemoveTheOpenRTB26Regs() { + public void makeHttpRequestsShouldPreserveTopLevel26RegsAndExtTypedFields() { // given final ExtRegsDsa dsa = ExtRegsDsa.of(2, 2, 3, emptyList()); - final BidRequest bidRequest = givenBidRequest(identity(), - requestBuilder -> requestBuilder.regs(Regs.builder() - .gdpr(1) - .usPrivacy("1YNN") - .gpp("gppconsent") - .gppSid(List.of(6)) - .ext(ExtRegs.of(null, null, "1", dsa)) - .build()).device(Device.builder().ua("UA").build())); + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder() + .gdpr(1) + .usPrivacy("1YNN") + .gpp("gppconsent") + .gppSid(List.of(6)) + .ext(ExtRegs.of(null, null, "1", dsa)) + .build()) + .device(Device.builder().ua("UA").build())); // when final Result>> result = target.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()).isEmpty(); - final Regs regs = result.getValue().getFirst().getPayload().getRegs(); - assertThat(regs.getGdpr()).isNull(); - assertThat(regs.getUsPrivacy()).isNull(); - assertThat(regs.getGpp()).isNull(); - assertThat(regs.getGppSid()).isNull(); - assertThat(regs.getExt()).isNotNull(); - assertThat(regs.getExt().getGdpr()).isEqualTo(1); - assertThat(regs.getExt().getUsPrivacy()).isEqualTo("1YNN"); - assertThat(regs.getExt().getGpc()).isEqualTo("1"); - assertThat(regs.getExt().getDsa()).isEqualTo(dsa); - assertThat(regs.getExt().getProperty("gpp").asText()).isEqualTo("gppconsent"); - assertThat(regs.getExt().getProperty("gpp_sid").get(0).asText()).isEqualTo("6"); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGdpr()).isEqualTo(1); + assertThat(regs.getUsPrivacy()).isEqualTo("1YNN"); + assertThat(regs.getGpp()).isEqualTo("gppconsent"); + assertThat(regs.getGppSid()).containsExactly(6); + assertThat(regs.getExt()).isEqualTo(ExtRegs.of(null, null, "1", dsa)); + }); } @Test - public void makeBidsShouldOverwriteRegsExtValues() { + public void makeHttpRequestsShouldPromoteLegacyExtGppAndGppSidToTopLevel() { // given - final BidRequest bidRequest = givenBidRequest(identity(), - requestBuilder -> requestBuilder.regs(Regs.builder() - .gdpr(1) - .ext(ExtRegs.of(0, "1YNN", null, null)) - .build()).device(Device.builder().ua("UA").build())); + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp", TextNode.valueOf("legacy_gpp_value")); + extRegs.addProperty("gpp_sid", mapper.valueToTree(List.of(6, 8))); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGpp()).isEqualTo("legacy_gpp_value"); + assertThat(regs.getGppSid()).containsExactly(6, 8); + assertThat(regs.getExt()).isNull(); + }); + } + + @Test + public void makeHttpRequestsShouldPromoteOnlyGppFromExtAndStripIt() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp", TextNode.valueOf("only_gpp")); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGpp()).isEqualTo("only_gpp"); + assertThat(regs.getGppSid()).isNull(); + assertThat(regs.getExt()).isNull(); + }); + } + + @Test + public void makeHttpRequestsShouldPreserveTopLevelGdprWhilePromotingGppFromExt() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp", TextNode.valueOf("mixed_gpp")); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().gdpr(1).ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGdpr()).isEqualTo(1); + assertThat(regs.getGpp()).isEqualTo("mixed_gpp"); + assertThat(regs.getExt()).isNull(); + }); + } + + @Test + public void makeHttpRequestsShouldKeepGpcAndUnrelatedExtPropertyAfterPromotion() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, "1", null); + extRegs.addProperty("gpp", TextNode.valueOf("with_gpc")); + extRegs.addProperty("unrelated", TextNode.valueOf("keep_me")); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + final ExtRegs expectedExt = ExtRegs.of(null, null, "1", null); + expectedExt.addProperty("unrelated", TextNode.valueOf("keep_me")); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGpp()).isEqualTo("with_gpc"); + assertThat(regs.getExt()).isEqualTo(expectedExt); + }); + } + + @Test + public void makeHttpRequestsShouldNotPromoteWhenExtPropertyHasWrongType() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp", IntNode.valueOf(99)); + extRegs.addProperty("gpp_sid", TextNode.valueOf("not_array")); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); // when final Result>> result = target.makeHttpRequests(bidRequest); // then + final ExtRegs expectedExt = ExtRegs.of(null, null, null, null); + expectedExt.addProperty("gpp", IntNode.valueOf(99)); + expectedExt.addProperty("gpp_sid", TextNode.valueOf("not_array")); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGpp()).isNull(); + assertThat(regs.getGppSid()).isNull(); + assertThat(regs.getExt()).isEqualTo(expectedExt); + }); + } + + @Test + public void makeHttpRequestsShouldLeaveMalformedExtValueInExtWhenSiblingFieldIsPromoted() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp_sid", mapper.valueToTree(List.of(6))); + extRegs.addProperty("gpp", IntNode.valueOf(99)); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + final ExtRegs expectedExt = ExtRegs.of(null, null, null, null); + expectedExt.addProperty("gpp", IntNode.valueOf(99)); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGppSid()).containsExactly(6); + assertThat(regs.getGpp()).isNull(); + assertThat(regs.getExt()).isEqualTo(expectedExt); + }); + } + + @Test + public void makeHttpRequestsShouldNotPromoteGppSidWhenArrayHasNonIntegerElement() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp_sid", mapper.valueToTree(List.of(7, "foo", 8))); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + final ExtRegs expectedExt = ExtRegs.of(null, null, null, null); + expectedExt.addProperty("gpp_sid", mapper.valueToTree(List.of(7, "foo", 8))); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGppSid()).isNull(); + assertThat(regs.getExt()).isEqualTo(expectedExt); + }); + } + + @Test + public void makeHttpRequestsShouldNotPromoteExtValuesThatDoNotFitInInt() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp_sid", mapper.valueToTree(List.of(7, 3_000_000_000L))); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + final ExtRegs expectedExt = ExtRegs.of(null, null, null, null); + expectedExt.addProperty("gpp_sid", mapper.valueToTree(List.of(7, 3_000_000_000L))); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGppSid()).isNull(); + assertThat(regs.getExt()).isEqualTo(expectedExt); + }); + } + + @Test + public void makeHttpRequestsShouldNotPromoteEmptyExtGppSidArray() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp_sid", mapper.createArrayNode()); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + final ExtRegs expectedExt = ExtRegs.of(null, null, null, null); + expectedExt.addProperty("gpp_sid", mapper.createArrayNode()); + assertThat(result.getErrors()).isEmpty(); - final Regs regs = result.getValue().getFirst().getPayload().getRegs(); - assertThat(regs.getGdpr()).isNull(); - assertThat(regs.getUsPrivacy()).isNull(); - assertThat(regs.getExt().getGdpr()).isEqualTo(1); - assertThat(regs.getExt().getUsPrivacy()).isEqualTo("1YNN"); - assertThat(regs.getExt().getDsa()).isNull(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGppSid()).isNull(); + assertThat(regs.getExt()).isEqualTo(expectedExt); + }); + } + + @Test + public void makeHttpRequestsShouldNotPromoteGppSidWhenArrayHasFractionalElement() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp_sid", mapper.valueToTree(List.of(6.5))); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + final ExtRegs expectedExt = ExtRegs.of(null, null, null, null); + expectedExt.addProperty("gpp_sid", mapper.valueToTree(List.of(6.5))); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGppSid()).isNull(); + assertThat(regs.getExt()).isEqualTo(expectedExt); + }); + } + + @Test + public void makeHttpRequestsShouldPromoteExtGppSidOverEmptyTopLevelArray() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp_sid", mapper.valueToTree(List.of(6))); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().gppSid(emptyList()).ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGppSid()).containsExactly(6); + assertThat(regs.getExt()).isNull(); + }); + } + + @Test + public void makeHttpRequestsShouldPromoteGppSidWhileTopLevelGppSupersedesItsExtCopy() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp", TextNode.valueOf("stale-ext-gpp")); + extRegs.addProperty("gpp_sid", mapper.valueToTree(List.of(6))); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().gpp("top-level-gpp").ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGpp()).isEqualTo("top-level-gpp"); + assertThat(regs.getGppSid()).containsExactly(6); + assertThat(regs.getExt()).isNull(); + }); + } + + @Test + public void makeHttpRequestsShouldReturnRegsUnchangedWhenExtHasOnlyUnrelatedProperties() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("customKey", TextNode.valueOf("keep_me")); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + final ExtRegs expectedExt = ExtRegs.of(null, null, null, null); + expectedExt.addProperty("customKey", TextNode.valueOf("keep_me")); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGpp()).isNull(); + assertThat(regs.getGppSid()).isNull(); + assertThat(regs.getExt()).isEqualTo(expectedExt); + }); + } + + @Test + public void makeHttpRequestsShouldDropExtGppWhenTopLevelGppAlreadySet() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp", TextNode.valueOf("ext-gpp")); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().gpp("top-level-gpp").ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGpp()).isEqualTo("top-level-gpp"); + assertThat(regs.getExt()).isNull(); + }); + } + + @Test + public void makeHttpRequestsShouldTreatEmptyTopLevelGppAsSet() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp", TextNode.valueOf("ext-gpp")); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().gpp("").ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGpp()).isEmpty(); + assertThat(regs.getExt()).isNull(); + }); + } + + @Test + public void makeHttpRequestsShouldDropExtGppSidWhenTopLevelGppSidAlreadySet() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp_sid", mapper.valueToTree(List.of(6))); + + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().gppSid(List.of(99)).ext(extRegs).build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGppSid()).containsExactly(99); + assertThat(regs.getExt()).isNull(); + }); + } + + @Test + public void makeHttpRequestsShouldApplyTheSamePromotedRegsToEveryImp() { + // given + final ExtRegs extRegs = ExtRegs.of(null, null, null, null); + extRegs.addProperty("gpp", TextNode.valueOf("shared-gpp")); + + final BidRequest bidRequest = BidRequest.builder() + .site(Site.builder().id("123").build()) + .imp(asList( + givenImp(impBuilder -> impBuilder.id("imp1")), + givenImp(impBuilder -> impBuilder.id("imp2")))) + .regs(Regs.builder().ext(extRegs).build()) + .device(Device.builder().ua("UA").build()) + .build(); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(2) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGpp()).isEqualTo("shared-gpp"); + assertThat(regs.getExt()).isNull(); + }); + } + + @Test + public void makeHttpRequestsShouldShortCircuitWhenRegsHasNoExt() { + // given + final BidRequest bidRequest = givenBidRequest( + identity(), + requestBuilder -> requestBuilder + .regs(Regs.builder().gdpr(0).gpp("already_top").build()) + .device(Device.builder().ua("UA").build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getRegs) + .allSatisfy(regs -> { + assertThat(regs.getGdpr()).isEqualTo(0); + assertThat(regs.getGpp()).isEqualTo("already_top"); + assertThat(regs.getExt()).isNull(); + }); } private static BidRequest givenBidRequest( diff --git a/src/test/java/org/prebid/server/bidder/yieldmo/YieldmoBidderTest.java b/src/test/java/org/prebid/server/bidder/yieldmo/YieldmoBidderTest.java index fcfc7964d10..5a656d8754e 100644 --- a/src/test/java/org/prebid/server/bidder/yieldmo/YieldmoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/yieldmo/YieldmoBidderTest.java @@ -206,8 +206,6 @@ public void makeHttpRequestShouldUseOriginalBidFloorsIfCurrencyCanNotBeConverted final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.bidfloor(BigDecimal.ONE).bidfloorcur("EUR")); - final var convertedBidFloor = new BigDecimal("1.5"); - when(currencyConversionService.convertCurrency(any(), any(), any(), any())).thenThrow( new PreBidException("currency could not be converted")); diff --git a/src/test/java/org/prebid/server/cookie/CookieDeprecationServiceTest.java b/src/test/java/org/prebid/server/cookie/CookieDeprecationServiceTest.java index da03b34ec0e..7a9ebd15191 100644 --- a/src/test/java/org/prebid/server/cookie/CookieDeprecationServiceTest.java +++ b/src/test/java/org/prebid/server/cookie/CookieDeprecationServiceTest.java @@ -168,7 +168,7 @@ public void updateBidRequestDeviceShouldNotChangeRequestAndDebugWarnWhenSecCooki // given final Map headers = Map.of( "header", "value", - "sec-cookie-deprecation", RandomStringUtils.random(101)); + "sec-cookie-deprecation", RandomStringUtils.insecure().next(101)); final List debugWarnings = new ArrayList<>(); final Account givenAccount = givenAccount(true, 100L); final AuctionContext auctionContext = givenContext(headers, givenAccount, debugWarnings); @@ -188,7 +188,7 @@ public void updateBidRequestDeviceShouldNotChangeRequestWhenDeviceExtCdepIsPrese // given final Map headers = Map.of( "header", "value", - "sec-cookie-deprecation", RandomStringUtils.random(100)); + "sec-cookie-deprecation", RandomStringUtils.insecure().next(100)); final List debugWarnings = new ArrayList<>(); final Account givenAccount = givenAccount(true, 100L); final AuctionContext auctionContext = givenContext(headers, givenAccount, debugWarnings); @@ -207,7 +207,7 @@ public void updateBidRequestDeviceShouldNotChangeRequestWhenAccountIsEmpty() { // given final Map headers = Map.of( "header", "value", - "sec-cookie-deprecation", RandomStringUtils.random(100)); + "sec-cookie-deprecation", RandomStringUtils.insecure().next(100)); final List debugWarnings = new ArrayList<>(); final Account givenAccount = Account.empty("accountId"); final AuctionContext auctionContext = givenContext(headers, givenAccount, debugWarnings); @@ -226,7 +226,7 @@ public void updateBidRequestDeviceShouldNotChangeRequestWhenCookieDeprecationIsN // given final Map headers = Map.of( "header", "value", - "sec-cookie-deprecation", RandomStringUtils.random(100)); + "sec-cookie-deprecation", RandomStringUtils.insecure().next(100)); final List debugWarnings = new ArrayList<>(); final Account givenAccount = givenAccount(null, null); final AuctionContext auctionContext = givenContext(headers, givenAccount, debugWarnings); @@ -245,7 +245,7 @@ public void updateBidRequestDeviceShouldNotChangeRequestWhenCookieDeprecationIsD // given final Map headers = Map.of( "header", "value", - "sec-cookie-deprecation", RandomStringUtils.random(100)); + "sec-cookie-deprecation", RandomStringUtils.insecure().next(100)); final List debugWarnings = new ArrayList<>(); final Account givenAccount = givenAccount(false, 100L); final AuctionContext auctionContext = givenContext(headers, givenAccount, debugWarnings); @@ -262,7 +262,7 @@ public void updateBidRequestDeviceShouldNotChangeRequestWhenCookieDeprecationIsD @Test public void updateBidRequestDeviceShouldAddCdepValueWhenDeviceExtIsAbsent() { // given - final String cdep = RandomStringUtils.random(100); + final String cdep = RandomStringUtils.insecure().next(100); final Map headers = Map.of( "header", "value", "sec-cookie-deprecation", cdep); @@ -282,7 +282,7 @@ public void updateBidRequestDeviceShouldAddCdepValueWhenDeviceExtIsAbsent() { @Test public void updateBidRequestDeviceShouldAddCdepValueWhenDeviceIsAbsent() { // given - final String cdep = RandomStringUtils.random(100); + final String cdep = RandomStringUtils.insecure().next(100); final Map headers = Map.of( "header", "value", "sec-cookie-deprecation", cdep); @@ -302,7 +302,7 @@ public void updateBidRequestDeviceShouldAddCdepValueWhenDeviceIsAbsent() { @Test public void updateBidRequestDeviceShouldAddCdepValueWhenDeviceExtIsPresentButWithoutCdep() { // given - final String cdep = RandomStringUtils.random(100); + final String cdep = RandomStringUtils.insecure().next(100); final Map headers = Map.of( "header", "value", "sec-cookie-deprecation", cdep); diff --git a/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java b/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java index 2f930fdf0de..9c7dcc002e6 100644 --- a/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java +++ b/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java @@ -6,6 +6,7 @@ import io.vertx.core.http.HttpServerRequest; import io.vertx.ext.web.RoutingContext; import org.assertj.core.api.Assertions; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -698,7 +699,7 @@ public void updateUidsCookieShouldRemoveAllExpiredUids() { .extracting(Uids::getUids) .extracting(Map::values) .extracting(ArrayList::new) - .asList() + .asInstanceOf(InstanceOfAssertFactories.LIST) .extracting(object -> (UidWithExpiry) object) .extracting(UidWithExpiry::getExpires) .allMatch(ZonedDateTime.now()::isBefore); diff --git a/src/test/java/org/prebid/server/execution/file/supplier/RemoteFileSupplierTest.java b/src/test/java/org/prebid/server/execution/file/supplier/RemoteFileSupplierTest.java index 076e03e0f03..260bc61bdd2 100644 --- a/src/test/java/org/prebid/server/execution/file/supplier/RemoteFileSupplierTest.java +++ b/src/test/java/org/prebid/server/execution/file/supplier/RemoteFileSupplierTest.java @@ -3,7 +3,6 @@ import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.file.AsyncFile; -import io.vertx.core.file.CopyOptions; import io.vertx.core.file.FileProps; import io.vertx.core.file.FileSystem; import io.vertx.core.http.HttpClient; @@ -136,9 +135,9 @@ public void getShouldReturnExpectedResult() { final AsyncFile tmpFile = mock(AsyncFile.class); given(fileSystem.open(eq(TMP_PATH), any())).willReturn(Future.succeededFuture(tmpFile)); given(fileSystem.exists(eq(SAVE_PATH))).willReturn(Future.succeededFuture(true)); - given(fileSystem.move(eq(SAVE_PATH), eq(BACKUP_PATH), Mockito.any())) + given(fileSystem.move(eq(SAVE_PATH), eq(BACKUP_PATH), Mockito.any())) .willReturn(Future.succeededFuture()); - given(fileSystem.move(eq(TMP_PATH), eq(SAVE_PATH), Mockito.any())) + given(fileSystem.move(eq(TMP_PATH), eq(SAVE_PATH), Mockito.any())) .willReturn(Future.succeededFuture()); given(getResponse.statusCode()).willReturn(200); @@ -166,9 +165,9 @@ public void getShouldReturnExpectedResultWhenCheckRemoteFileSizeIsTrue() { final AsyncFile tmpFile = mock(AsyncFile.class); given(fileSystem.open(eq(TMP_PATH), any())).willReturn(Future.succeededFuture(tmpFile)); - given(fileSystem.move(eq(SAVE_PATH), eq(BACKUP_PATH), Mockito.any())) + given(fileSystem.move(eq(SAVE_PATH), eq(BACKUP_PATH), Mockito.any())) .willReturn(Future.succeededFuture()); - given(fileSystem.move(eq(TMP_PATH), eq(SAVE_PATH), Mockito.any())) + given(fileSystem.move(eq(TMP_PATH), eq(SAVE_PATH), Mockito.any())) .willReturn(Future.succeededFuture()); given(getResponse.statusCode()).willReturn(200); diff --git a/src/test/java/org/prebid/server/execution/file/syncer/RemoteFileSyncerTest.java b/src/test/java/org/prebid/server/execution/file/syncer/RemoteFileSyncerTest.java index 33bef039bab..e9c737aa971 100644 --- a/src/test/java/org/prebid/server/execution/file/syncer/RemoteFileSyncerTest.java +++ b/src/test/java/org/prebid/server/execution/file/syncer/RemoteFileSyncerTest.java @@ -546,19 +546,6 @@ private void givenTriggerUpdate() { .willReturn(123L); } - @SuppressWarnings("unchecked") - private static Answer withSelfAndPassObjectToHandler(T obj, int index) { - return inv -> { - // invoking handler right away passing mock to it - ((Handler) inv.getArgument(index)).handle(obj); - return inv.getMock(); - }; - } - - private static Answer withSelfAndPassObjectToHandler(T obj) { - return withSelfAndPassObjectToHandler(obj, 1); - } - @SuppressWarnings("unchecked") private static Answer withReturnObjectAndPassObjectToHandler(T obj, V ret, int index) { return inv -> { diff --git a/src/test/java/org/prebid/server/floors/BasicPriceFloorEnforcerTest.java b/src/test/java/org/prebid/server/floors/BasicPriceFloorEnforcerTest.java index 9b5a08bc41b..fa279e38550 100644 --- a/src/test/java/org/prebid/server/floors/BasicPriceFloorEnforcerTest.java +++ b/src/test/java/org/prebid/server/floors/BasicPriceFloorEnforcerTest.java @@ -9,11 +9,11 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.auction.model.AuctionParticipation; +import org.prebid.server.auction.model.BidRejection; import org.prebid.server.auction.model.BidRejectionReason; import org.prebid.server.auction.model.BidRejectionTracker; import org.prebid.server.auction.model.BidderRequest; import org.prebid.server.auction.model.BidderResponse; -import org.prebid.server.auction.model.BidRejection; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderError; import org.prebid.server.bidder.model.BidderSeatBid; @@ -348,7 +348,7 @@ public void shouldRejectBidsHavingPriceBelowFloor() { Bid.builder().id("bidId2").impid("impId2").price(BigDecimal.TEN).build(), null, null)), singletonList(BidderError.of( "Bid with id 'bidId1' was rejected by floor enforcement: " - + "price 1 is below the floor 1.1", + + "price 1 is below the floor 1.1", BidderError.Type.rejected_ipf, singleton("impId1")))); } diff --git a/src/test/java/org/prebid/server/floors/BasicPriceFloorProcessorTest.java b/src/test/java/org/prebid/server/floors/BasicPriceFloorProcessorTest.java index f70471b1b4d..1664d83e554 100644 --- a/src/test/java/org/prebid/server/floors/BasicPriceFloorProcessorTest.java +++ b/src/test/java/org/prebid/server/floors/BasicPriceFloorProcessorTest.java @@ -115,13 +115,13 @@ public void shouldUseFloorsDataFromProviderIfPresent() { // then assertThat(extractFloors(result)).isEqualTo(givenFloors(floors -> floors - .enabled(true) - .skipped(false) - .floorProvider("provider.com") - .floorMin(BigDecimal.ONE) - .data(providerFloorsData) - .fetchStatus(FetchStatus.success) - .location(PriceFloorLocation.fetch))); + .enabled(true) + .skipped(false) + .floorProvider("provider.com") + .floorMin(BigDecimal.ONE) + .data(providerFloorsData) + .fetchStatus(FetchStatus.success) + .location(PriceFloorLocation.fetch))); verifyNoInteractions(metrics); } @@ -143,12 +143,12 @@ public void shouldUseFloorsFromProviderIfUseDynamicDataAndUseFetchDataRateAreAbs // then assertThat(extractFloors(result)).isEqualTo(givenFloors(floors -> floors - .enabled(true) - .skipped(false) - .floorProvider("provider.com") - .data(providerFloorsData) - .fetchStatus(FetchStatus.success) - .location(PriceFloorLocation.fetch))); + .enabled(true) + .skipped(false) + .floorProvider("provider.com") + .data(providerFloorsData) + .fetchStatus(FetchStatus.success) + .location(PriceFloorLocation.fetch))); verifyNoInteractions(metrics); } @@ -250,13 +250,13 @@ public void shouldUseFloorsFromProviderIfUseDynamicDataIsTrueAndUseFetchDataRate // then assertThat(extractFloors(result)).isEqualTo(givenFloors(floors -> floors - .enabled(true) - .skipped(false) - .floorProvider("provider.com") - .data(providerFloorsData) - .floorMin(BigDecimal.ONE) - .fetchStatus(FetchStatus.success) - .location(PriceFloorLocation.fetch))); + .enabled(true) + .skipped(false) + .floorProvider("provider.com") + .data(providerFloorsData) + .floorMin(BigDecimal.ONE) + .fetchStatus(FetchStatus.success) + .location(PriceFloorLocation.fetch))); verifyNoInteractions(metrics); } @@ -598,14 +598,14 @@ public void shouldMergeProviderWithRequestFloors() { // then assertThat(extractFloors(result)).isEqualTo(givenFloors(floors -> floors - .enabled(true) - .skipped(false) - .floorProvider("provider.com") - .enforcement(PriceFloorEnforcement.builder().enforcePbs(false).enforceRate(100).build()) - .data(providerFloorsData) - .floorMin(BigDecimal.ONE) - .fetchStatus(FetchStatus.success) - .location(PriceFloorLocation.fetch))); + .enabled(true) + .skipped(false) + .floorProvider("provider.com") + .enforcement(PriceFloorEnforcement.builder().enforcePbs(false).enforceRate(100).build()) + .data(providerFloorsData) + .floorMin(BigDecimal.ONE) + .fetchStatus(FetchStatus.success) + .location(PriceFloorLocation.fetch))); } @Test @@ -626,12 +626,12 @@ public void shouldReturnProviderFloorsWhenNotEnabledByRequestAndEnforceRateAndFl // then final PriceFloorRules expectedResult = givenFloors(floors -> floors - .enabled(true) - .skipped(false) - .floorProvider("provider.com") - .data(providerFloorsData) - .fetchStatus(FetchStatus.success) - .location(PriceFloorLocation.fetch)); + .enabled(true) + .skipped(false) + .floorProvider("provider.com") + .data(providerFloorsData) + .fetchStatus(FetchStatus.success) + .location(PriceFloorLocation.fetch)); assertThat(extractFloors(result)).isEqualTo(expectedResult); } @@ -1024,9 +1024,9 @@ public void shouldUpdateImpsIfBidFloorResolved() { ExtImpPrebidFloors.of("rule", BigDecimal.ONE, BigDecimal.TEN, BigDecimal.TEN, "CUR")); assertThat(extractImps(result)).containsOnly(givenImp(imp -> imp - .bidfloor(BigDecimal.TEN) - .bidfloorcur("USD") - .ext(ext.set("prebid", extPrebid.set("floors", extPrebidFloors))))); + .bidfloor(BigDecimal.TEN) + .bidfloorcur("USD") + .ext(ext.set("prebid", extPrebid.set("floors", extPrebidFloors))))); } @Test diff --git a/src/test/java/org/prebid/server/it/AdswagTest.java b/src/test/java/org/prebid/server/it/AdswagTest.java new file mode 100644 index 00000000000..a80748e57ad --- /dev/null +++ b/src/test/java/org/prebid/server/it/AdswagTest.java @@ -0,0 +1,32 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class AdswagTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromAdswag() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adswag-exchange")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/adswag/test-adswag-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/adswag/test-adswag-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/adswag/test-auction-adswag-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/adswag/test-auction-adswag-response.json", response, singletonList("adswag")); + } +} diff --git a/src/test/java/org/prebid/server/it/AppMonstaMediaTest.java b/src/test/java/org/prebid/server/it/AppMonstaMediaTest.java new file mode 100644 index 00000000000..2c00ea3362f --- /dev/null +++ b/src/test/java/org/prebid/server/it/AppMonstaMediaTest.java @@ -0,0 +1,36 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; +import java.util.List; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; + +public class AppMonstaMediaTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromAppMonstaMedia() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/appMonstaMedia-exchange/")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/appMonstaMedia/test-appMonstaMedia-bid-request.json"))) + .willReturn(aResponse() + .withBody(jsonFrom("openrtb2/appMonstaMedia/test-appMonstaMedia-bid-response.json")))); + + // when + final Response response = responseFor( + "openrtb2/appMonstaMedia/test-auction-appMonstaMedia-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/appMonstaMedia/test-auction-appMonstaMedia-response.json", response, + List.of("appMonstaMedia")); + } + +} diff --git a/src/test/java/org/prebid/server/it/ApplicationTest.java b/src/test/java/org/prebid/server/it/ApplicationTest.java index e6e0baf5525..344cf4cab18 100644 --- a/src/test/java/org/prebid/server/it/ApplicationTest.java +++ b/src/test/java/org/prebid/server/it/ApplicationTest.java @@ -17,6 +17,7 @@ import io.restassured.response.Response; import io.restassured.specification.RequestSpecification; import org.apache.commons.collections4.CollectionUtils; +import org.assertj.core.api.InstanceOfAssertFactories; import org.hamcrest.Matchers; import org.json.JSONException; import org.junit.jupiter.api.Test; @@ -369,7 +370,7 @@ public void setuidShouldUpdateRubiconUidInUidCookie() throws IOException { assertThat(uids.getUids()) .extracting(Map::keySet) .extracting(ArrayList::new) - .asList() + .asInstanceOf(InstanceOfAssertFactories.LIST) .containsExactly(MAGNITE_COOKIE); assertThat(uids.getUids().get(MAGNITE_COOKIE).getUid()).isEqualTo("updatedUid"); assertThat(uids.getUids().get(MAGNITE_COOKIE).getExpires().toInstant()) diff --git a/src/test/java/org/prebid/server/it/BidwaveTest.java b/src/test/java/org/prebid/server/it/BidwaveTest.java new file mode 100644 index 00000000000..3ad87828e83 --- /dev/null +++ b/src/test/java/org/prebid/server/it/BidwaveTest.java @@ -0,0 +1,32 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class BidwaveTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromBidwave() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/bidwave-exchange")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/bidwave/test-bidwave-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/bidwave/test-bidwave-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/bidwave/test-auction-bidwave-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/bidwave/test-auction-bidwave-response.json", response, singletonList("bidwave")); + } +} diff --git a/src/test/java/org/prebid/server/it/CadentApertureMxTest.java b/src/test/java/org/prebid/server/it/CadentApertureMxTest.java index cc062921a3a..326ec4e91c5 100644 --- a/src/test/java/org/prebid/server/it/CadentApertureMxTest.java +++ b/src/test/java/org/prebid/server/it/CadentApertureMxTest.java @@ -19,9 +19,10 @@ public class CadentApertureMxTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromCadentApertureMx() throws IOException, JSONException { // given WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cadent_aperture_mx-exchange")) - .withRequestBody( - equalToJson(jsonFrom("openrtb2/cadentaperturemx/test-cadentaperturemx-bid-request.json"), - true, false)) + .withRequestBody(equalToJson( + jsonFrom("openrtb2/cadentaperturemx/test-cadentaperturemx-bid-request.json"), + true, + false)) .willReturn(aResponse().withBody( jsonFrom("openrtb2/cadentaperturemx/test-cadentaperturemx-bid-response.json")))); diff --git a/src/test/java/org/prebid/server/it/EskimiTest.java b/src/test/java/org/prebid/server/it/EskimiTest.java new file mode 100644 index 00000000000..dbfa588ceec --- /dev/null +++ b/src/test/java/org/prebid/server/it/EskimiTest.java @@ -0,0 +1,33 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class EskimiTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromEskimi() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/eskimi-exchange")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/eskimi/test-eskimi-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/eskimi/test-eskimi-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/eskimi/test-auction-eskimi-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/eskimi/test-auction-eskimi-response.json", response, + singletonList("eskimi")); + } +} diff --git a/src/test/java/org/prebid/server/it/FloxisTest.java b/src/test/java/org/prebid/server/it/FloxisTest.java new file mode 100644 index 00000000000..429948bfb45 --- /dev/null +++ b/src/test/java/org/prebid/server/it/FloxisTest.java @@ -0,0 +1,32 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class FloxisTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromFloxis() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/floxis-exchange")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/floxis/test-floxis-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/floxis/test-floxis-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/floxis/test-auction-floxis-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/floxis/test-auction-floxis-response.json", response, singletonList("floxis")); + } +} diff --git a/src/test/java/org/prebid/server/it/IntegrationTest.java b/src/test/java/org/prebid/server/it/IntegrationTest.java index 6b9c6dbe83f..3271bee989e 100644 --- a/src/test/java/org/prebid/server/it/IntegrationTest.java +++ b/src/test/java/org/prebid/server/it/IntegrationTest.java @@ -1,11 +1,9 @@ package org.prebid.server.it; import com.fasterxml.jackson.databind.JsonNode; -import com.github.tomakehurst.wiremock.common.FileSource; -import com.github.tomakehurst.wiremock.extension.Parameters; -import com.github.tomakehurst.wiremock.extension.ResponseTransformer; -import com.github.tomakehurst.wiremock.http.Request; +import com.github.tomakehurst.wiremock.extension.ResponseTransformerV2; import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import com.github.tomakehurst.wiremock.stubbing.ServeEvent; import io.restassured.builder.RequestSpecBuilder; import io.restassured.config.ObjectMapperConfig; import io.restassured.config.RestAssuredConfig; @@ -271,24 +269,24 @@ static BidCacheRequestPattern equalToBidCacheRequest(String json) { return new BidCacheRequestPattern(json); } - public static class CacheResponseTransformer extends ResponseTransformer { + public static class CacheResponseTransformer implements ResponseTransformerV2 { @Override public com.github.tomakehurst.wiremock.http.Response transform( - Request request, com.github.tomakehurst.wiremock.http.Response response, FileSource files, - Parameters parameters) { + com.github.tomakehurst.wiremock.http.Response response, ServeEvent serveEvent) { final String newResponse; try { newResponse = cacheResponseFromRequestJson( - request.getBodyAsString(), - parameters.getString("matcherName")); + serveEvent.getRequest().getBodyAsString(), + serveEvent.getTransformerParameters().getString("matcherName")); } catch (IOException e) { return com.github.tomakehurst.wiremock.http.Response.response() .body(e.getMessage()) .status(500) .build(); } + return com.github.tomakehurst.wiremock.http.Response.response().body(newResponse).status(200).build(); } diff --git a/src/test/java/org/prebid/server/it/PrecisoTest.java b/src/test/java/org/prebid/server/it/PrecisoTest.java index 3bcba9a210f..9896c99e654 100644 --- a/src/test/java/org/prebid/server/it/PrecisoTest.java +++ b/src/test/java/org/prebid/server/it/PrecisoTest.java @@ -19,10 +19,10 @@ public class PrecisoTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromPreciso() throws IOException, JSONException { // given WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/preciso-exchange")) - .withRequestBody(equalToJson(jsonFrom( - "openrtb2/preciso/test-preciso-bid-request.json"))) - .willReturn(aResponse().withBody(jsonFrom( - "openrtb2/preciso/test-preciso-bid-response.json")))); + .withRequestBody(equalToJson(jsonFrom( + "openrtb2/preciso/test-preciso-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom( + "openrtb2/preciso/test-preciso-bid-response.json")))); // when final Response response = responseFor("openrtb2/preciso/test-auction-preciso-request.json", diff --git a/src/test/java/org/prebid/server/it/ScaliburTest.java b/src/test/java/org/prebid/server/it/ScaliburTest.java new file mode 100644 index 00000000000..cd33f769458 --- /dev/null +++ b/src/test/java/org/prebid/server/it/ScaliburTest.java @@ -0,0 +1,33 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; +import java.util.List; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; + +public class ScaliburTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromScalibur() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/scalibur-exchange")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/scalibur/test-scalibur-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/scalibur/test-scalibur-bid-response.json")))); + + // when + final Response response = responseFor( + "openrtb2/scalibur/test-auction-scalibur-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/scalibur/test-auction-scalibur-response.json", response, List.of("scalibur")); + } +} diff --git a/src/test/java/org/prebid/server/it/SevioTest.java b/src/test/java/org/prebid/server/it/SevioTest.java new file mode 100644 index 00000000000..d3cb42b7e53 --- /dev/null +++ b/src/test/java/org/prebid/server/it/SevioTest.java @@ -0,0 +1,37 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class SevioTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromSevio() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/sevio-exchange")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/sevio/test-sevio-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/sevio/test-sevio-bid-response.json")))); + + // when + final Response response = responseFor( + "openrtb2/sevio/test-auction-sevio-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals( + "openrtb2/sevio/test-auction-sevio-response.json", + response, + singletonList("sevio")); + } + +} diff --git a/src/test/java/org/prebid/server/it/SparteoTest.java b/src/test/java/org/prebid/server/it/SparteoTest.java index 713cf35fee1..37b39d0a4a4 100644 --- a/src/test/java/org/prebid/server/it/SparteoTest.java +++ b/src/test/java/org/prebid/server/it/SparteoTest.java @@ -19,9 +19,9 @@ public void openrtb2AuctionShouldRespondWithBidsFromSparteoBanner() throws Excep .withQueryParam("network_id", equalTo("networkId")) .withQueryParam("site_domain", equalTo("dev.sparteo.com")) .withRequestBody(equalToJson( - jsonFrom("openrtb2/sparteo/test-sparteo-bid-request.json"))) + jsonFrom("openrtb2/sparteo/test-sparteo-bid-request.json"))) .willReturn(aResponse().withBody( - jsonFrom("openrtb2/sparteo/test-sparteo-bid-response.json")))); + jsonFrom("openrtb2/sparteo/test-sparteo-bid-response.json")))); final Response response = responseFor( "openrtb2/sparteo/test-auction-sparteo-request.json", diff --git a/src/test/java/org/prebid/server/it/SynapseHXTest.java b/src/test/java/org/prebid/server/it/SynapseHXTest.java new file mode 100644 index 00000000000..8d7d51957e4 --- /dev/null +++ b/src/test/java/org/prebid/server/it/SynapseHXTest.java @@ -0,0 +1,33 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class SynapseHXTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromSynapseHX() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/synapsehx-exchange")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/synapsehx/test-synapsehx-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/synapsehx/test-synapsehx-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/synapsehx/test-auction-synapsehx-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/synapsehx/test-auction-synapsehx-response.json", + response, singletonList("synapsehx")); + } +} diff --git a/src/test/java/org/prebid/server/it/hooks/SampleItEntrypointHook.java b/src/test/java/org/prebid/server/it/hooks/SampleItEntrypointHook.java index a4011db9106..189a056897a 100644 --- a/src/test/java/org/prebid/server/it/hooks/SampleItEntrypointHook.java +++ b/src/test/java/org/prebid/server/it/hooks/SampleItEntrypointHook.java @@ -1,7 +1,7 @@ package org.prebid.server.it.hooks; import io.vertx.core.Future; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.prebid.server.hooks.execution.v1.entrypoint.EntrypointPayloadImpl; import org.prebid.server.hooks.v1.InvocationContext; import org.prebid.server.hooks.v1.InvocationResult; @@ -27,11 +27,11 @@ public Future> call( private Future> maybeUpdate(EntrypointPayload entrypointPayload) { final String updateSelector = entrypointPayload.queryParams().get("sample-it-module-update"); - final CaseInsensitiveMultiMap updatedHeaders = StringUtils.contains(updateSelector, "headers") + final CaseInsensitiveMultiMap updatedHeaders = Strings.CS.contains(updateSelector, "headers") ? updateHeaders(entrypointPayload.headers()) : entrypointPayload.headers(); - final String updatedBody = StringUtils.contains(updateSelector, "body") + final String updatedBody = Strings.CS.contains(updateSelector, "body") ? updateBody(entrypointPayload.body()) : entrypointPayload.body(); @@ -49,7 +49,7 @@ private static CaseInsensitiveMultiMap updateHeaders(CaseInsensitiveMultiMap hea } private static String updateBody(String body) { - return body.replaceAll("\"language\":\"en\"", "\"language\":\"fr\""); + return body.replace("\"language\":\"en\"", "\"language\":\"fr\""); } @Override diff --git a/src/test/java/org/prebid/server/json/deserializer/AccountActivityRulesConfigDeserializerTest.java b/src/test/java/org/prebid/server/json/deserializer/AccountActivityRulesConfigDeserializerTest.java index fc9d015c5e2..63c0dfb580c 100644 --- a/src/test/java/org/prebid/server/json/deserializer/AccountActivityRulesConfigDeserializerTest.java +++ b/src/test/java/org/prebid/server/json/deserializer/AccountActivityRulesConfigDeserializerTest.java @@ -48,7 +48,7 @@ public void setUp() { public void deserializeShouldThrowExceptionOnWrongJsonToken() throws IOException { // given given(parser.getCurrentToken()).willReturn(JsonToken.VALUE_FALSE); - given(parser.getCurrentName()).willReturn("FIELD"); + given(parser.currentName()).willReturn("FIELD"); doThrow(RuntimeException.class) .when(context) .reportWrongTokenException( diff --git a/src/test/java/org/prebid/server/json/deserializer/CommaSeparatedStringAsListOfIntegersDeserializerTest.java b/src/test/java/org/prebid/server/json/deserializer/CommaSeparatedStringAsListOfIntegersDeserializerTest.java index da97e42d911..c11a261605f 100644 --- a/src/test/java/org/prebid/server/json/deserializer/CommaSeparatedStringAsListOfIntegersDeserializerTest.java +++ b/src/test/java/org/prebid/server/json/deserializer/CommaSeparatedStringAsListOfIntegersDeserializerTest.java @@ -39,7 +39,7 @@ public void setUp() { public void deserializeShouldThrowExceptionOnWrongJsonToken() throws IOException { // given given(parser.getCurrentToken()).willReturn(JsonToken.VALUE_FALSE); - given(parser.getCurrentName()).willReturn("FIELD"); + given(parser.currentName()).willReturn("FIELD"); doThrow(RuntimeException.class) .when(context) .reportWrongTokenException( @@ -59,7 +59,7 @@ public void deserializeShouldThrowExceptionOnNullValue() throws IOException { // given given(parser.getCurrentToken()).willReturn(JsonToken.VALUE_STRING); given(parser.getValueAsString()).willReturn(null); - given(parser.getCurrentName()).willReturn("FIELD"); + given(parser.currentName()).willReturn("FIELD"); doThrow(RuntimeException.class) .when(context) .reportWrongTokenException( @@ -79,7 +79,7 @@ public void deserializeShouldThrowExceptionOnInvalidValue() throws IOException { // given given(parser.getCurrentToken()).willReturn(JsonToken.VALUE_STRING); given(parser.getValueAsString()).willReturn("invalid"); - given(parser.getCurrentName()).willReturn("FIELD"); + given(parser.currentName()).willReturn("FIELD"); doThrow(RuntimeException.class) .when(context) .reportPropertyInputMismatch( diff --git a/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java b/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java index cb585197c6d..64863606f8b 100644 --- a/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java +++ b/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java @@ -22,7 +22,7 @@ public class ConditionalLoggerTest { @Spy - private Logger logger = LoggerFactory.getLogger(ConditionalLoggerTest.class); + private final Logger logger = LoggerFactory.getLogger(ConditionalLoggerTest.class); private Vertx vertx; diff --git a/src/test/java/org/prebid/server/metric/MetricsTest.java b/src/test/java/org/prebid/server/metric/MetricsTest.java index 0eed97eab2d..79b434ec4d4 100644 --- a/src/test/java/org/prebid/server/metric/MetricsTest.java +++ b/src/test/java/org/prebid/server/metric/MetricsTest.java @@ -601,6 +601,15 @@ public void updateAdapterRequestGotbidsMetricsShouldIncrementMetrics() { .isEqualTo(2); } + @Test + public void updateAccountRequestGotbidsMetricsShouldIncrementMetric() { + // when + metrics.updateAccountRequestGotbidsMetric(ACCOUNT_ID); + + // then + assertThat(metricRegistry.counter("account.accountId.requests.gotbids").getCount()).isOne(); + } + @Test public void updateAdapterBidMetricsShouldUpdateMetrics() { // when diff --git a/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java b/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java index 854db8fcef0..cf329b645fb 100644 --- a/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java +++ b/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java @@ -71,7 +71,7 @@ public class VendorListServiceTest extends VertxTest { private VendorListService target; @BeforeEach - public void setUp() throws JsonProcessingException { + public void setUp() { given(bidderCatalog.knownVendorIds()).willReturn(singleton(52)); given(fetchThrottler.registerFetchAttempt(anyInt())).willReturn(true); given(vendorListFileStore.readFallbackVendorList(isNull())).willReturn(null); diff --git a/src/test/java/org/prebid/server/validation/BidderParamValidatorTest.java b/src/test/java/org/prebid/server/validation/BidderParamValidatorTest.java index cc47c8a376b..3d2d8add847 100644 --- a/src/test/java/org/prebid/server/validation/BidderParamValidatorTest.java +++ b/src/test/java/org/prebid/server/validation/BidderParamValidatorTest.java @@ -15,8 +15,8 @@ import org.prebid.server.proto.openrtb.ext.request.audiencenetwork.ExtImpAudienceNetwork; import org.prebid.server.proto.openrtb.ext.request.beachfront.ExtImpBeachfront; import org.prebid.server.proto.openrtb.ext.request.eplanning.ExtImpEplanning; -import org.prebid.server.proto.openrtb.ext.request.openx.ExtImpOpenx; import org.prebid.server.proto.openrtb.ext.request.magnite.ExtImpMagnite; +import org.prebid.server.proto.openrtb.ext.request.openx.ExtImpOpenx; import org.prebid.server.proto.openrtb.ext.request.sovrn.ExtImpSovrn; import org.prebid.server.spring.config.bidder.model.CompressionType; import org.prebid.server.spring.config.bidder.model.Ortb; @@ -355,7 +355,7 @@ public void schemaShouldReturnSchemasString() throws IOException { // then assertThat(result).isEqualTo(ResourceUtil.readFromClasspath( - "org/prebid/server/validation/schema//valid/test-schemas.json")); + "org/prebid/server/validation/schema/valid/test-schemas.json")); } @Test diff --git a/src/test/java/org/prebid/server/validation/ImpValidatorTest.java b/src/test/java/org/prebid/server/validation/ImpValidatorTest.java index bbc329fbd07..22287e1e23a 100644 --- a/src/test/java/org/prebid/server/validation/ImpValidatorTest.java +++ b/src/test/java/org/prebid/server/validation/ImpValidatorTest.java @@ -1298,15 +1298,15 @@ public void validateImpsShouldReturnValidationMessageWhenMetricTypeNullOrEmpty() } @Test - public void validateImpsShouldReturnValidationMessageWhenMetricValueIsNotValid() { + public void validateImpsShouldReturnValidationMessageWhenMetricValueNullOrEmpty() { // given final List givenImps = singletonList(validImpBuilder() - .metric(singletonList(Metric.builder().type("viewability").value(2.0f).build())).build()); + .metric(singletonList(Metric.builder().type("viewability").value(null).build())).build()); // when & then assertThatThrownBy(() -> target.validateImps(givenImps, Collections.emptyMap(), null)) .isInstanceOf(ValidationException.class) - .hasMessage("request.imp[0].metric[0].value must be in the range [0.0, 1.0]"); + .hasMessage("Missing request.imp[0].metric[0].value"); } @Test @@ -1607,8 +1607,7 @@ public void validateImpsShouldReturnNoMessageWhenImpExtPrebidImpBidderIsAlias() } @Test - public void validateImpsShouldReturnValidationMessageWhenExtImpPrebidHasStoredAuctionResponseWithoutId() - throws ValidationException { + public void validateImpsShouldReturnValidationMessageWhenExtImpPrebidHasStoredAuctionResponseWithoutId() { // given final List givenImps = singletonList(validImpBuilder() @@ -1623,8 +1622,7 @@ public void validateImpsShouldReturnValidationMessageWhenExtImpPrebidHasStoredAu } @Test - public void validateImpsShouldNotReturnValidationMessageWhenStoredAuctionResponseWithoutIdAndWithSeatBidObj() - throws ValidationException { + public void validateImpsShouldNotReturnValidationMessageWhenStoredAuctionResponseWithoutIdAndWithSeatBidObj() { // given final List givenImps = singletonList(validImpBuilder() @@ -2370,15 +2368,15 @@ public void validateImpShouldReturnValidationMessageWhenMetricTypeNullOrEmpty() } @Test - public void validateImpShouldReturnValidationMessageWhenMetricValueIsNotValid() { + public void validateImpShouldReturnValidationMessageWhenMetricValueNullOrEmpty() { // given final Imp givenImp = validImpBuilder() - .metric(singletonList(Metric.builder().type("viewability").value(2.0f).build())).build(); + .metric(singletonList(Metric.builder().type("viewability").value(null).build())).build(); // when & then assertThatThrownBy(() -> target.validateImp(givenImp)) .isInstanceOf(ValidationException.class) - .hasMessage("imp[id=200].metric[0].value must be in the range [0.0, 1.0]"); + .hasMessage("Missing imp[id=200].metric[0].value"); } private static List givenImps(UnaryOperator nativeCustomizer) { diff --git a/src/test/java/org/prebid/server/validation/ResponseBidValidatorTest.java b/src/test/java/org/prebid/server/validation/ResponseBidValidatorTest.java index df429612cdc..7316c3d6914 100644 --- a/src/test/java/org/prebid/server/validation/ResponseBidValidatorTest.java +++ b/src/test/java/org/prebid/server/validation/ResponseBidValidatorTest.java @@ -14,8 +14,8 @@ import org.prebid.server.VertxTest; import org.prebid.server.auction.aliases.BidderAliases; import org.prebid.server.auction.model.AuctionContext; -import org.prebid.server.auction.model.BidRejectionTracker; import org.prebid.server.auction.model.BidRejection; +import org.prebid.server.auction.model.BidRejectionTracker; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.metric.MetricName; import org.prebid.server.metric.Metrics; diff --git a/src/test/resources/org/prebid/server/it/amp/test-cache-request.json b/src/test/resources/org/prebid/server/it/amp/test-cache-request.json index 8f94e6c3fc8..4e1ca810c2d 100644 --- a/src/test/resources/org/prebid/server/it/amp/test-cache-request.json +++ b/src/test/resources/org/prebid/server/it/amp/test-cache-request.json @@ -30,7 +30,7 @@ "origbidcpm": 12.09 } }, - "aid":"tid", + "aid": "tid", "ttlseconds": 300 }, { @@ -67,7 +67,7 @@ "origbidcur": "USD" } }, - "aid":"tid", + "aid": "tid", "ttlseconds": 300 } ] diff --git a/src/test/resources/org/prebid/server/it/amp/test-genericAlias-bid-request.json b/src/test/resources/org/prebid/server/it/amp/test-genericAlias-bid-request.json index 298cb731f04..6d88f384408 100644 --- a/src/test/resources/org/prebid/server/it/amp/test-genericAlias-bid-request.json +++ b/src/test/resources/org/prebid/server/it/amp/test-genericAlias-bid-request.json @@ -22,7 +22,7 @@ }, "tid": "${json-unit.any-string}", "bidder": { - "property1" : "value1" + "property1": "value1" } } } diff --git a/src/test/resources/org/prebid/server/it/cache/update/test-generic-bid-request1.json b/src/test/resources/org/prebid/server/it/cache/update/test-generic-bid-request1.json index 437d09d25f4..02f31d2480d 100644 --- a/src/test/resources/org/prebid/server/it/cache/update/test-generic-bid-request1.json +++ b/src/test/resources/org/prebid/server/it/cache/update/test-generic-bid-request1.json @@ -17,7 +17,7 @@ "ext": { "tid": "${json-unit.any-string}", "bidder": { - "property1" : "value1" + "property1": "value1" }, "prebid": { "storedrequest": { diff --git a/src/test/resources/org/prebid/server/it/cache/update/test-genericAlias-bid-request2.json b/src/test/resources/org/prebid/server/it/cache/update/test-genericAlias-bid-request2.json index d341a0e4e76..3c064932e9d 100644 --- a/src/test/resources/org/prebid/server/it/cache/update/test-genericAlias-bid-request2.json +++ b/src/test/resources/org/prebid/server/it/cache/update/test-genericAlias-bid-request2.json @@ -32,7 +32,7 @@ }, "tid": "${json-unit.any-string}", "bidder": { - "property2" : "value2" + "property2": "value2" } } } diff --git a/src/test/resources/org/prebid/server/it/hooks/reject/test-generic-bid-request.json b/src/test/resources/org/prebid/server/it/hooks/reject/test-generic-bid-request.json index b6f7e741add..5437b19307e 100644 --- a/src/test/resources/org/prebid/server/it/hooks/reject/test-generic-bid-request.json +++ b/src/test/resources/org/prebid/server/it/hooks/reject/test-generic-bid-request.json @@ -43,11 +43,13 @@ "gdpr": 0 } }, - "at" : 1, - "tmax" : "${json-unit.any-number}", - "cur" : [ "USD" ], - "source" : { - "tid" : "${json-unit.any-string}" + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/info-bidders/test-info-bidder-details-response.json b/src/test/resources/org/prebid/server/it/info-bidders/test-info-bidder-details-response.json index b682ccc253d..f5708f5182e 100644 --- a/src/test/resources/org/prebid/server/it/info-bidders/test-info-bidder-details-response.json +++ b/src/test/resources/org/prebid/server/it/info-bidders/test-info-bidder-details-response.json @@ -1,5 +1,5 @@ { - "status":"ACTIVE", + "status": "ACTIVE", "usesHttps": false, "maintainer": { "email": "header-bidding@magnite.com" diff --git a/src/test/resources/org/prebid/server/it/openrtb2/aax/test-aax-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/aax/test-aax-bid-response.json index 87543ca7bf5..cd9d5b25d34 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/aax/test-aax-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/aax/test-aax-bid-response.json @@ -1,20 +1,20 @@ - { +{ "id": "tid", "seatbid": [ { "seat": "aax", "bid": [ - { - "id": "randomid", - "impid": "test-imp-id", - "price": 0.500000, - "adid": "12345678", - "adm": "some-test-ad", - "cid": "987", - "crid": "12345678", - "h": 250, - "w": 300 - } + { + "id": "randomid", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300 + } ] } ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adagio/test-adagio-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adagio/test-adagio-bid-request.json index c6f877d20bc..6682800b0ad 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adagio/test-adagio-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adagio/test-adagio-bid-request.json @@ -11,7 +11,7 @@ "ext": { "tid": "${json-unit.any-string}", "bidder": { - "organizationId" : "organizationId", + "organizationId": "organizationId", "placement": "placement" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adagio/test-auction-adagio-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adagio/test-auction-adagio-request.json index 3a07c1ece20..76d8c19d603 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adagio/test-auction-adagio-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adagio/test-auction-adagio-request.json @@ -9,7 +9,7 @@ }, "ext": { "adagio": { - "organizationId" : "organizationId", + "organizationId": "organizationId", "placement": "placement" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adf/test-auction-adf-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adf/test-auction-adf-response.json index 70a4616692e..d50ebb88925 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adf/test-auction-adf-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adf/test-auction-adf-response.json @@ -7,7 +7,7 @@ "id": "bid_id", "impid": "imp_id", "exp": 300, - "price": 11.393, + "price": 11.393, "adomain": [ ], "crid": "test-creative-id-1", @@ -27,7 +27,7 @@ "id": "bid_id_banner", "impid": "imp_id_banner", "exp": 300, - "price": 11.393, + "price": 11.393, "adomain": [], "adm": "", "crid": "test-creative-id-2", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adhese/test-adhese-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adhese/test-adhese-bid-request.json index 886be9c2fd3..02cb9d17805 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adhese/test-adhese-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adhese/test-adhese-bid-request.json @@ -1,62 +1,65 @@ - { - "id" : "request_id", - "imp" : [ { - "id" : "imp_id", - "banner" : { - "w" : 300, - "h" : 250 - }, - "secure" : 1, - "ext" : { - "adhese" : { - "SL": [ - "_adhese_prebid_demo_-leaderboard" - ], - "ag": [ - "55" - ], - "ci": [ - "gent", - "brussels" - ], - "tl": [ - "all" - ] + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 250 + }, + "secure": 1, + "ext": { + "adhese": { + "SL": [ + "_adhese_prebid_demo_-leaderboard" + ], + "ag": [ + "55" + ], + "ci": [ + "gent", + "brussels" + ], + "tl": [ + "all" + ] + } } } - } ], - "site" : { - "domain" : "www.example.com", - "page" : "http://www.example.com", - "publisher" : { - "domain" : "example.com" + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" }, - "ext" : { - "amp" : 0 + "ext": { + "amp": 0 } }, - "device" : { - "ua" : "userAgent", - "ip" : "193.168.244.1" + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" }, - "at" : 1, - "tmax" : "${json-unit.any-number}", - "cur" : [ "USD" ], - "source" : { - "tid" : "${json-unit.any-string}" + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" }, - "regs" : { - "ext" : { - "gdpr" : 0 + "regs": { + "ext": { + "gdpr": 0 } }, - "ext" : { - "prebid" : { - "server" : { - "externalurl" : "http://localhost:8080", - "gvlid" : 1, - "datacenter" : "local", + "ext": { + "prebid": { + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", "http_method": "POST", "endpoint": "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/openrtb2/auction" } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adnuntius/test-adnuntius-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adnuntius/test-adnuntius-bid-request.json index 7d075275a7b..4a300f14917 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adnuntius/test-adnuntius-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adnuntius/test-adnuntius-bid-request.json @@ -15,7 +15,7 @@ "usi": "user_d" }, "context": "some_page", - "kv" : { - "any" : "any" + "kv": { + "any": "any" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-adswag-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-adswag-bid-request.json new file mode 100644 index 00000000000..152741f4075 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-adswag-bid-request.json @@ -0,0 +1,69 @@ +{ + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "secure": 1, + "ext": { + "tid": "${json-unit.any-string}", + "adswag": { + "placement_id": "prebid-test-display" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "prebid-test", + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "dnt": 0, + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en" + }, + "user": { + "id": "demo-user" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "EUR" + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "regs": { + "gdpr": 0 + }, + "ext": { + "prebid": { + "channel": { + "name": "web" + }, + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", + "http_method": "POST", + "endpoint": "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/openrtb2/auction" + } + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-adswag-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-adswag-bid-response.json new file mode 100644 index 00000000000..226446907dc --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-adswag-bid-response.json @@ -0,0 +1,27 @@ +{ + "id": "test-request-banner", + "cur": "EUR", + "seatbid": [ + { + "seat": "adswag", + "bid": [ + { + "id": "req-abc-1", + "impid": "test-imp-banner", + "price": 2.50, + "burl": "https://ads.adswag.ai/v1/win?sc=c2ln&sig=YWJj&price=${AUCTION_PRICE}", + "cid": "cmp-test-1", + "crid": "cr-test-1", + "adomain": [ + "advertiser.example" + ], + "ext": { + "adswag": { + "serve_url": "https://ads.adswag.ai/v1/ad?sc=c2ln&sig=YWJj" + } + } + } + ] + } + ] +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-auction-adswag-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-auction-adswag-request.json new file mode 100644 index 00000000000..3b0d048f183 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-auction-adswag-request.json @@ -0,0 +1,47 @@ +{ + "id": "test-request-banner", + "imp": [ + { + "id": "test-imp-banner", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "adswag": { + "publisherId": "prebid-test", + "placementId": "prebid-test-display" + } + } + } + ], + "site": { + "id": "demo-site", + "domain": "example.com", + "page": "https://example.com/demo", + "publisher": { + "id": "demo-publisher" + } + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "ip": "192.0.2.1", + "language": "en", + "dnt": 0 + }, + "user": { + "id": "demo-user" + }, + "cur": [ + "EUR" + ], + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-auction-adswag-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-auction-adswag-response.json new file mode 100644 index 00000000000..35bd69f82ce --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/adswag/test-auction-adswag-response.json @@ -0,0 +1,50 @@ +{ + "id": "test-request-banner", + "seatbid": [ + { + "seat": "adswag", + "bid": [ + { + "id": "req-abc-1", + "impid": "test-imp-banner", + "price": 2.50, + "burl": "https://ads.adswag.ai/v1/win?sc=c2ln&sig=YWJj&price=${AUCTION_PRICE}", + "cid": "cmp-test-1", + "crid": "cr-test-1", + "adomain": [ + "advertiser.example" + ], + "adm": "", + "w": 300, + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "adswag": { + "serve_url": "https://ads.adswag.ai/v1/ad?sc=c2ln&sig=YWJj" + }, + "origbidcpm": 2.50, + "origbidcur": "EUR", + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "adswag" + } + } + } + } + ], + "group": 0 + } + ], + "cur": "EUR", + "ext": { + "responsetimemillis": { + "adswag": "{{ adswag.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 0 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adyoulike/test-auction-adyoulike-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adyoulike/test-auction-adyoulike-response.json index 1c403a36179..6875bf29d7e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adyoulike/test-auction-adyoulike-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adyoulike/test-auction-adyoulike-response.json @@ -22,7 +22,7 @@ } }, "origbidcpm": 3.33, - "origbidcur" : "USD" + "origbidcur": "USD" } } ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/akcelo/test-akcelo-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/akcelo/test-akcelo-bid-request.json index 2e4de27209d..557dc4e531c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/akcelo/test-akcelo-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/akcelo/test-akcelo-bid-request.json @@ -52,15 +52,15 @@ "gdpr": 0 } }, - "ext" : { - "prebid" : { - "channel" : { - "name" : "web" + "ext": { + "prebid": { + "channel": { + "name": "web" }, - "server" : { - "externalurl" : "http://localhost:8080", - "gvlid" : 1, - "datacenter" : "local", + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", "http_method": "POST", "endpoint": "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/openrtb2/auction" } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-appMonstaMedia-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-appMonstaMedia-bid-request.json new file mode 100644 index 00000000000..3f7a5e60358 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-appMonstaMedia-bid-request.json @@ -0,0 +1,57 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 250 + }, + "secure": 1, + "ext": { + "bidder": { + "type": "publisher", + "placementId": "testPlacementId" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "prebid": { + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", + "http_method": "POST", + "endpoint": "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/openrtb2/auction" + } + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-appMonstaMedia-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-appMonstaMedia-bid-response.json new file mode 100644 index 00000000000..180173549d8 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-appMonstaMedia-bid-response.json @@ -0,0 +1,21 @@ +{ + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 3.33, + "crid": "creativeId", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-auction-appMonstaMedia-request.json b/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-auction-appMonstaMedia-request.json new file mode 100644 index 00000000000..dfc6fa5eb8b --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-auction-appMonstaMedia-request.json @@ -0,0 +1,23 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "appMonstaMedia": { + "placementId": "testPlacementId" + } + } + } + ], + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-auction-appMonstaMedia-response.json b/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-auction-appMonstaMedia-response.json new file mode 100644 index 00000000000..a35eca173d9 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/appMonstaMedia/test-auction-appMonstaMedia-response.json @@ -0,0 +1,38 @@ +{ + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "exp": 300, + "price": 3.33, + "crid": "creativeId", + "mtype": 1, + "ext": { + "origbidcpm": 3.33, + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "appMonstaMedia" + } + } + } + } + ], + "seat": "appMonstaMedia", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "appMonstaMedia": "{{ appMonstaMedia.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 0 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/appnexus/test-video-appnexus-bid-response-1.json b/src/test/resources/org/prebid/server/it/openrtb2/appnexus/test-video-appnexus-bid-response-1.json index 1e6cb5473d5..eae51d1d09e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/appnexus/test-video-appnexus-bid-response-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/appnexus/test-video-appnexus-bid-response-1.json @@ -10,7 +10,9 @@ "price": 5.5, "adid": "29681110", "adm": "some-test-ad", - "cat" : ["1-cat"], + "cat": [ + "1-cat" + ], "adomain": [ "appnexus.com" ], @@ -20,7 +22,7 @@ "ext": { "appnexus": { "brand_id": 1, - "brand_category_id" : 1, + "brand_category_id": 1, "auction_id": 8189378542222915032, "bidder_id": 2, "bid_ad_type": 1, @@ -34,7 +36,9 @@ "price": 2.7, "adid": "2961238", "adm": "some-test-ad-2", - "cat" : ["2-cat"], + "cat": [ + "2-cat" + ], "adomain": [ "appnexus.com" ], @@ -44,7 +48,7 @@ "ext": { "appnexus": { "brand_id": 1, - "brand_category_id" : 2, + "brand_category_id": 2, "auction_id": 8189378542222915032, "bidder_id": 2, "bid_ad_type": 1, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/appnexus/test-video-appnexus-bid-response-2.json b/src/test/resources/org/prebid/server/it/openrtb2/appnexus/test-video-appnexus-bid-response-2.json index f7c26c18243..d3e6bb0eeb7 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/appnexus/test-video-appnexus-bid-response-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/appnexus/test-video-appnexus-bid-response-2.json @@ -10,7 +10,9 @@ "price": 2, "adid": "2938", "adm": "some-test-ad-3", - "cat" : ["3-cat"], + "cat": [ + "3-cat" + ], "adomain": [ "appnexus.com" ], @@ -20,7 +22,7 @@ "ext": { "appnexus": { "brand_id": 1, - "brand_category_id" : 3, + "brand_category_id": 3, "auction_id": 8189378542222915032, "bidder_id": 2, "bid_ad_type": 1, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/aso/test-aso-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/aso/test-aso-bid-request.json index 7df0474d049..9699b58402d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/aso/test-aso-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/aso/test-aso-bid-request.json @@ -10,8 +10,8 @@ }, "ext": { "tid": "${json-unit.any-string}", - "bidder" : { - "zone" : 1 + "bidder": { + "zone": 1 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/aso/test-auction-aso-request.json b/src/test/resources/org/prebid/server/it/openrtb2/aso/test-auction-aso-request.json index 396436aead1..e47eb617b1f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/aso/test-auction-aso-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/aso/test-auction-aso-request.json @@ -9,7 +9,7 @@ }, "ext": { "aso": { - "zone" : 1 + "zone": 1 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bcmint/test-auction-bcmint-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bcmint/test-auction-bcmint-request.json index 9d97ef6cb6c..b11e7ec0a3f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bcmint/test-auction-bcmint-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bcmint/test-auction-bcmint-request.json @@ -9,7 +9,7 @@ }, "ext": { "bcmint": { - "zone" : 1 + "zone": 1 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bcmint/test-bcmint-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bcmint/test-bcmint-bid-request.json index 7df0474d049..9699b58402d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bcmint/test-bcmint-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bcmint/test-bcmint-bid-request.json @@ -10,8 +10,8 @@ }, "ext": { "tid": "${json-unit.any-string}", - "bidder" : { - "zone" : 1 + "bidder": { + "zone": 1 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bematterfull/test-bematterfull-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bematterfull/test-bematterfull-bid-request.json index 5f252c56bce..adbaa4ae4e6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bematterfull/test-bematterfull-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bematterfull/test-bematterfull-bid-request.json @@ -10,9 +10,9 @@ }, "ext": { "tid": "${json-unit.any-string}", - "bidder" : { - "env" : "testHost", - "pid" : "testPid" + "bidder": { + "env": "testHost", + "pid": "testPid" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/beop/test-beop-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/beop/test-beop-bid-request.json index 14647847299..dbb02128757 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/beop/test-beop-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/beop/test-beop-bid-request.json @@ -32,9 +32,11 @@ }, "at": 1, "tmax": "${json-unit.any-number}", - "cur": ["USD"], - "source" : { - "tid" : "${json-unit.any-string}" + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" }, "regs": { "gdpr": 0 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/beyondmedia/test-beyondmedia-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/beyondmedia/test-beyondmedia-bid-request.json index d3848f87820..9fd295cb7d6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/beyondmedia/test-beyondmedia-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/beyondmedia/test-beyondmedia-bid-request.json @@ -13,7 +13,7 @@ }, "ext": { "bidder": { - "type" : "publisher", + "type": "publisher", "placementId": "test" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidgency/test-auction-bidgency-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bidgency/test-auction-bidgency-request.json index 03b942cc803..33996956434 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bidgency/test-auction-bidgency-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidgency/test-auction-bidgency-request.json @@ -9,7 +9,7 @@ }, "ext": { "bidgency": { - "zone" : 1 + "zone": 1 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidgency/test-bidgency-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bidgency/test-bidgency-bid-request.json index 7df0474d049..9699b58402d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bidgency/test-bidgency-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidgency/test-bidgency-bid-request.json @@ -10,8 +10,8 @@ }, "ext": { "tid": "${json-unit.any-string}", - "bidder" : { - "zone" : 1 + "bidder": { + "zone": 1 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidscube/test-bidscube-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bidscube/test-bidscube-bid-request.json index 098717eebf0..cd1d7e729b2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bidscube/test-bidscube-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidscube/test-bidscube-bid-request.json @@ -3,7 +3,7 @@ "imp": [ { "id": "imp_id", - "secure" : 1, + "secure": 1, "banner": { "w": 300, "h": 250 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidtheatre/test-auction-bidtheatre-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bidtheatre/test-auction-bidtheatre-request.json index fc53d5f98b9..5337b4b4c21 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bidtheatre/test-auction-bidtheatre-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidtheatre/test-auction-bidtheatre-request.json @@ -9,7 +9,7 @@ }, "ext": { "bidtheatre": { - "publisherId" : "73b20b3a-12a0-4869-b54e-8d42b55786ee" + "publisherId": "73b20b3a-12a0-4869-b54e-8d42b55786ee" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidtheatre/test-bidtheatre-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bidtheatre/test-bidtheatre-bid-request.json index 5f040a668b5..5fca237cfe1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bidtheatre/test-bidtheatre-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidtheatre/test-bidtheatre-bid-request.json @@ -10,8 +10,8 @@ }, "ext": { "tid": "${json-unit.any-string}", - "bidder" : { - "publisherId" : "73b20b3a-12a0-4869-b54e-8d42b55786ee" + "bidder": { + "publisherId": "73b20b3a-12a0-4869-b54e-8d42b55786ee" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-auction-bidwave-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-auction-bidwave-request.json new file mode 100644 index 00000000000..26df715cbd5 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-auction-bidwave-request.json @@ -0,0 +1,23 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidwave": { + "publisherId": "11111111-1111-4111-8111-111111111111" + } + } + } + ], + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-auction-bidwave-response.json b/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-auction-bidwave-response.json new file mode 100644 index 00000000000..59c661d9251 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-auction-bidwave-response.json @@ -0,0 +1,44 @@ +{ + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "exp": 300, + "price": 3.33, + "adm": "adm001", + "adid": "adid001", + "cid": "cid001", + "crid": "crid001", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "bidwave" + } + }, + "origbidcpm": 3.33, + "origbidcur": "USD" + } + } + ], + "seat": "bidwave", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "bidwave": "{{ bidwave.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 0 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-bidwave-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-bidwave-bid-request.json new file mode 100644 index 00000000000..31beccb6312 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-bidwave-bid-request.json @@ -0,0 +1,58 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "secure": 1, + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "publisherId": "11111111-1111-4111-8111-111111111111" + } + } + } + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "regs": { + "gdpr": 0 + }, + "ext": { + "prebid": { + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", + "http_method": "POST", + "endpoint": "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/openrtb2/auction" + } + }, + "bidwave": { + "pid": "11111111-1111-4111-8111-111111111111" + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-bidwave-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-bidwave-bid-response.json new file mode 100644 index 00000000000..6df6c15a57d --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/bidwave/test-bidwave-bid-response.json @@ -0,0 +1,22 @@ +{ + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 3.33, + "adid": "adid001", + "crid": "crid001", + "cid": "cid001", + "adm": "adm001", + "mtype": 1, + "h": 250, + "w": 300 + } + ] + } + ], + "cur": "USD" +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bluesea/test-auction-bluesea-response.json b/src/test/resources/org/prebid/server/it/openrtb2/bluesea/test-auction-bluesea-response.json index a855aaabb71..95e0585cd72 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bluesea/test-auction-bluesea-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bluesea/test-auction-bluesea-response.json @@ -13,7 +13,7 @@ "w": 300, "h": 250, "ext": { - "mediatype":"banner", + "mediatype": "banner", "prebid": { "type": "banner", "meta": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bluesea/test-bluesea-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/bluesea/test-bluesea-bid-response.json index 7aba40dd965..5f7d8216e89 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bluesea/test-bluesea-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bluesea/test-bluesea-bid-response.json @@ -11,8 +11,8 @@ "adm": "adm001", "h": 250, "w": 300, - "ext":{ - "mediatype":"banner" + "ext": { + "mediatype": "banner" } } ] diff --git a/src/test/resources/org/prebid/server/it/openrtb2/boldwin/test-boldwin-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/boldwin/test-boldwin-bid-request.json index 9bc0c815069..adaedbb69f6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/boldwin/test-boldwin-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/boldwin/test-boldwin-bid-request.json @@ -13,7 +13,7 @@ }, "ext": { "bidder": { - "type" : "network", + "type": "network", "endpointId": "test" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/bwx/test-bwx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/bwx/test-bwx-bid-request.json index d0c0b64f79c..04a8aa3dc1f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/bwx/test-bwx-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/bwx/test-bwx-bid-request.json @@ -7,11 +7,11 @@ "w": 320, "h": 250 }, - "secure" : 1, - "ext" : { - "tid" : "${json-unit.any-string}", - "bidder" : { - "pid" : "somePlacementId" + "secure": 1, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "pid": "somePlacementId" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ccx/test-auction-ccx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/ccx/test-auction-ccx-response.json index f285ee8bfca..fb2809051af 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ccx/test-auction-ccx-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ccx/test-auction-ccx-response.json @@ -20,7 +20,7 @@ "type": "standard" }, "adm": "some-test-ad-1", - "adomain":[ + "adomain": [ "somedomain.com" ], "w": 300, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ccx/test-ccx-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/ccx/test-ccx-bid-response.json index 0f0c1da3026..b2e5a593e8c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ccx/test-ccx-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ccx/test-ccx-bid-response.json @@ -9,7 +9,7 @@ "price": 3.33, "crid": "creativeId", "adm": "some-test-ad-1", - "adomain":[ + "adomain": [ "somedomain.com" ], "w": 300, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/colossus/test-auction-colossus-response.json b/src/test/resources/org/prebid/server/it/openrtb2/colossus/test-auction-colossus-response.json index 00b82c6832c..1d383f6e27a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/colossus/test-auction-colossus-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/colossus/test-auction-colossus-response.json @@ -19,7 +19,7 @@ "adaptercode": "colossus" } }, - "mediaType" : "banner", + "mediaType": "banner", "origbidcpm": 1.25 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/colossus/test-colossus-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/colossus/test-colossus-bid-response.json index 40d72eb1a98..5a49b20bab3 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/colossus/test-colossus-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/colossus/test-colossus-bid-response.json @@ -12,7 +12,7 @@ "h": 250, "w": 300, "ext": { - "mediaType" : "banner" + "mediaType": "banner" } } ] diff --git a/src/test/resources/org/prebid/server/it/openrtb2/compass/test-compass-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/compass/test-compass-bid-request.json index 9bc0c815069..adaedbb69f6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/compass/test-compass-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/compass/test-compass-bid-request.json @@ -13,7 +13,7 @@ }, "ext": { "bidder": { - "type" : "network", + "type": "network", "endpointId": "test" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connectad/test-connectad-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connectad/test-connectad-bid-request.json index 66e6fdbeddc..bd9651297b2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/connectad/test-connectad-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/connectad/test-connectad-bid-request.json @@ -3,7 +3,7 @@ "imp": [ { "id": "imp_id", - "secure": 1, + "secure": 0, "banner": { "w": 300, "h": 250 @@ -11,14 +11,15 @@ "tagid": "15", "bidfloor": 14.7, "bidfloorcur": "USD", - "secure": 0, "ext": { "tid": "${json-unit.any-string}", "bidder": { "networkId": "12", "siteId": "15", "bidfloor": 14.7 - } + }, + "networkId": "12", + "siteId": "15" } } ], @@ -45,9 +46,7 @@ "USD" ], "regs": { - "ext": { - "gdpr": 0 - } + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-consumable-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-consumable-bid-request.json index 08a1d30da1d..a6570b33632 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-consumable-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-consumable-bid-request.json @@ -52,7 +52,9 @@ } }, "at": 1, - "cur": ["USD"], + "cur": [ + "USD" + ], "tmax": "${json-unit.any-number}", "source": { "tid": "${json-unit.any-string}" diff --git a/src/test/resources/org/prebid/server/it/openrtb2/criteo/test-criteo-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/criteo/test-criteo-bid-request.json index 8a4fecfe4ad..6c571673472 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/criteo/test-criteo-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/criteo/test-criteo-bid-request.json @@ -41,7 +41,7 @@ "ip": "193.168.244.1" }, "regs": { - "gdpr": 0 + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/definemedia/test-auction-definemedia-response.json b/src/test/resources/org/prebid/server/it/openrtb2/definemedia/test-auction-definemedia-response.json index 381bc91c43e..c57713f7c00 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/definemedia/test-auction-definemedia-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/definemedia/test-auction-definemedia-response.json @@ -7,7 +7,7 @@ "id": "bid_id", "impid": "imp_id", "exp": 300, - "price": 11.393, + "price": 11.393, "adomain": [ ], "crid": "test-creative-id-1", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/dianomi/test-auction-dianomi-response.json b/src/test/resources/org/prebid/server/it/openrtb2/dianomi/test-auction-dianomi-response.json index 3ce055440ed..b01a0e9e17e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/dianomi/test-auction-dianomi-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/dianomi/test-auction-dianomi-response.json @@ -7,7 +7,7 @@ "id": "bid_id_banner", "impid": "imp_id_banner", "exp": 300, - "price": 11.393, + "price": 11.393, "adomain": [], "adm": "", "crid": "test-creative-id-2", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/dianomi/test-dianomi-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/dianomi/test-dianomi-bid-request.json index e4b6fc93657..a4e468a4578 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/dianomi/test-dianomi-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/dianomi/test-dianomi-bid-request.json @@ -4,7 +4,7 @@ { "id": "imp_id_banner", "secure": 1, - "tagid" : "12345", + "tagid": "12345", "banner": { "format": [ { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/edge226/test-edge226-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/edge226/test-edge226-bid-request.json index 05195e65132..a1ec2c35084 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/edge226/test-edge226-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/edge226/test-edge226-bid-request.json @@ -8,10 +8,10 @@ "w": 320, "h": 250 }, - "ext" : { - "bidder" : { - "type" : "publisher", - "placementId" : "placementid" + "ext": { + "bidder": { + "type": "publisher", + "placementId": "placementid" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/elementaltv/test-elementaltv-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/elementaltv/test-elementaltv-bid-request-1.json index ca2410186f2..649b93e59a1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/elementaltv/test-elementaltv-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/elementaltv/test-elementaltv-bid-request-1.json @@ -39,7 +39,7 @@ "USD" ], "regs": { - "gdpr" : 0 + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/emtv/test-emtv-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/emtv/test-emtv-bid-request.json index 9bc0c815069..adaedbb69f6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/emtv/test-emtv-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/emtv/test-emtv-bid-request.json @@ -13,7 +13,7 @@ }, "ext": { "bidder": { - "type" : "network", + "type": "network", "endpointId": "test" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/epsilon/alias/test-epsilon-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/epsilon/alias/test-epsilon-bid-request.json index 691523fe2bd..5d9a03a1feb 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/epsilon/alias/test-epsilon-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/epsilon/alias/test-epsilon-bid-request.json @@ -43,7 +43,7 @@ "USD" ], "regs": { - "gdpr": 0 + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/epsilon/test-epsilon-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/epsilon/test-epsilon-bid-request.json index 13d607ba8b3..d9934ec0791 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/epsilon/test-epsilon-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/epsilon/test-epsilon-bid-request.json @@ -43,7 +43,7 @@ "USD" ], "regs": { - "gdpr": 0 + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-auction-eskimi-request.json b/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-auction-eskimi-request.json new file mode 100644 index 00000000000..bec343ed7bc --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-auction-eskimi-request.json @@ -0,0 +1,24 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 800, + "h": 600 + }, + "ext": { + "eskimi": { + "placementId": 123 + } + } + } + ], + "tmax": 5000, + "regs": { + "gdpr": 0 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-auction-eskimi-response.json b/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-auction-eskimi-response.json new file mode 100644 index 00000000000..d0d85f706e7 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-auction-eskimi-response.json @@ -0,0 +1,41 @@ +{ + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "exp": 1500, + "price": 1.25, + "adm": "adm001", + "crid": "crid", + "w": 800, + "h": 600, + "mtype": 2, + "ext": { + "prebid": { + "type": "video", + "meta": { + "adaptercode": "eskimi" + } + }, + "origbidcpm": 1.25 + } + } + ], + "seat": "eskimi", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "eskimi": "{{ eskimi.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 0 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-eskimi-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-eskimi-bid-request.json new file mode 100644 index 00000000000..584712b7332 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-eskimi-bid-request.json @@ -0,0 +1,59 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "secure": 1, + "video": { + "mimes": [ + "video/mp4" + ], + "w": 800, + "h": 600 + }, + "ext": { + "tid" : "${json-unit.any-string}", + "bidder": { + "placementId": 123 + } + } + } + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "placementId" : 123, + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "regs": { + "gdpr": 0 + }, + "ext": { + "prebid": { + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", + "http_method": "POST", + "endpoint": "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/openrtb2/auction" + } + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-eskimi-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-eskimi-bid-response.json new file mode 100644 index 00000000000..b00165a1652 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/eskimi/test-eskimi-bid-response.json @@ -0,0 +1,20 @@ +{ + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "adm001", + "h": 600, + "w": 800, + "mtype": 2 + } + ] + } + ], + "bidid": "bid001" +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/feedad/test-auction-feedad-response.json b/src/test/resources/org/prebid/server/it/openrtb2/feedad/test-auction-feedad-response.json index 2ef3414f19f..b35cd3305c5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/feedad/test-auction-feedad-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/feedad/test-auction-feedad-response.json @@ -19,7 +19,7 @@ "ext": { "prebid": { "type": "banner", - "meta":{ + "meta": { "adaptercode": "feedad" } }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/feedad/test-feedad-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/feedad/test-feedad-bid-request.json index 27d13f76122..d91fb380f45 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/feedad/test-feedad-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/feedad/test-feedad-bid-request.json @@ -40,8 +40,10 @@ }, "at": 1, "tmax": "${json-unit.any-number}", - "cur": ["USD"], - "source" : { + "cur": [ + "USD" + ], + "source": { "tid": "${json-unit.any-string}" }, "regs": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/flatads/test-auction-flatads-response.json b/src/test/resources/org/prebid/server/it/openrtb2/flatads/test-auction-flatads-response.json index 2b648367e50..ab18593019a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/flatads/test-auction-flatads-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/flatads/test-auction-flatads-response.json @@ -19,7 +19,7 @@ "ext": { "prebid": { "type": "banner", - "meta":{ + "meta": { "adaptercode": "flatads" } }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/floors/floors-test-auction-response.json b/src/test/resources/org/prebid/server/it/openrtb2/floors/floors-test-auction-response.json index d74037d285a..91a5992251c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/floors/floors-test-auction-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/floors/floors-test-auction-response.json @@ -18,7 +18,7 @@ } }, "origbidcpm": 13, - "origbidcur":"GBP" + "origbidcur": "GBP" } } ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-auction-floxis-request.json b/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-auction-floxis-request.json new file mode 100644 index 00000000000..4ce042710fa --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-auction-floxis-request.json @@ -0,0 +1,35 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "floxis": { + "seat": "pub-seat-1" + } + } + } + ], + "source": { + "schain": { + "complete": 1, + "ver": "1.0", + "nodes": [ + { + "asi": "floxis.tech", + "sid": "pub-seat-1", + "hp": 1 + } + ] + } + }, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-auction-floxis-response.json b/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-auction-floxis-response.json new file mode 100644 index 00000000000..07b4c9cb073 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-auction-floxis-response.json @@ -0,0 +1,44 @@ +{ + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 3.33, + "adm": "adm001", + "adid": "adid001", + "cid": "cid001", + "crid": "crid001", + "w": 300, + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "floxis" + } + }, + "origbidcpm": 3.33, + "origbidcur": "USD" + } + } + ], + "seat": "floxis", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "floxis": "{{ floxis.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 0 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-floxis-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-floxis-bid-request.json new file mode 100644 index 00000000000..cf7ba733859 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-floxis-bid-request.json @@ -0,0 +1,66 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "secure": 1, + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "seat": "pub-seat-1" + } + } + } + ], + "source": { + "tid": "${json-unit.any-string}", + "schain": { + "complete": 1, + "ver": "1.0", + "nodes": [ + { + "asi": "floxis.tech", + "sid": "pub-seat-1", + "hp": 1 + } + ] + } + }, + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "regs": { + "gdpr": 0 + }, + "ext": { + "prebid": { + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", + "http_method": "POST", + "endpoint": "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/openrtb2/auction" + } + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-floxis-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-floxis-bid-response.json new file mode 100644 index 00000000000..c9c23670bfa --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/floxis/test-floxis-bid-response.json @@ -0,0 +1,23 @@ +{ + "id": "request_id", + "cur": "USD", + "seatbid": [ + { + "seat": "floxis", + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 3.33, + "adid": "adid001", + "crid": "crid001", + "cid": "cid001", + "adm": "adm001", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-auction-freewheel-ssp-request.json b/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-auction-freewheel-ssp-request.json index 4a2ec336ea6..219047034a0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-auction-freewheel-ssp-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-auction-freewheel-ssp-request.json @@ -4,7 +4,9 @@ { "id": "imp-1", "video": { - "mimes": ["video/mp4"], + "mimes": [ + "video/mp4" + ], "w": 300, "h": 250 }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-freewheel-ssp-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-freewheel-ssp-bid-request.json index 7a97e3b4b4e..f520921092d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-freewheel-ssp-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-freewheel-ssp-bid-request.json @@ -38,8 +38,8 @@ "cur": [ "USD" ], - "regs" : { - "gdpr" : 0 + "regs": { + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-freewheel-ssp-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-freewheel-ssp-bid-response.json index 89bcc9a611b..fb4c6a5b06d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-freewheel-ssp-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/freewheel-ssp/test-freewheel-ssp-bid-response.json @@ -4,13 +4,13 @@ { "bid": [ { - "id": "12345_freewheelssp-test_1", - "impid": "imp-1", - "price": 1.0, - "adid": "7857", - "adm": "", - "cid": "4001", - "crid": "7857" + "id": "12345_freewheelssp-test_1", + "impid": "imp-1", + "price": 1.0, + "adid": "7857", + "adm": "", + "cid": "4001", + "crid": "7857" } ], "type": "video" diff --git a/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-auction-freewheelssp-request.json b/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-auction-freewheelssp-request.json index 670c85e0201..9c907b3ffc2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-auction-freewheelssp-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-auction-freewheelssp-request.json @@ -4,7 +4,9 @@ { "id": "imp-1", "video": { - "mimes": ["video/mp4"], + "mimes": [ + "video/mp4" + ], "w": 300, "h": 250 }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-freewheelssp-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-freewheelssp-bid-request.json index 7a97e3b4b4e..f520921092d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-freewheelssp-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-freewheelssp-bid-request.json @@ -38,8 +38,8 @@ "cur": [ "USD" ], - "regs" : { - "gdpr" : 0 + "regs": { + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-freewheelssp-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-freewheelssp-bid-response.json index 89bcc9a611b..fb4c6a5b06d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-freewheelssp-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/freewheelssp/test-freewheelssp-bid-response.json @@ -4,13 +4,13 @@ { "bid": [ { - "id": "12345_freewheelssp-test_1", - "impid": "imp-1", - "price": 1.0, - "adid": "7857", - "adm": "", - "cid": "4001", - "crid": "7857" + "id": "12345_freewheelssp-test_1", + "impid": "imp-1", + "price": 1.0, + "adid": "7857", + "adm": "", + "cid": "4001", + "crid": "7857" } ], "type": "video" diff --git a/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-auction-fwssp-request.json b/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-auction-fwssp-request.json index e0feff74147..7ec84c685f6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-auction-fwssp-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-auction-fwssp-request.json @@ -4,7 +4,9 @@ { "id": "imp-1", "video": { - "mimes": ["video/mp4"], + "mimes": [ + "video/mp4" + ], "w": 300, "h": 250 }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-fwssp-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-fwssp-bid-request.json index f05c17d81af..eb74756740e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-fwssp-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-fwssp-bid-request.json @@ -40,8 +40,8 @@ "cur": [ "USD" ], - "regs" : { - "gdpr" : 0 + "regs": { + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-fwssp-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-fwssp-bid-response.json index 4ad4c804c45..b4fff41dc3e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-fwssp-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/fwssp/test-fwssp-bid-response.json @@ -4,13 +4,13 @@ { "bid": [ { - "id": "12345_fwssp-test_1", - "impid": "imp-1", - "price": 1.0, - "adid": "7857", - "adm": "", - "cid": "4001", - "crid": "7857" + "id": "12345_fwssp-test_1", + "impid": "imp-1", + "price": 1.0, + "adid": "7857", + "adm": "", + "cid": "4001", + "crid": "7857" } ], "type": "video" diff --git a/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-auction-generic-request.json b/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-auction-generic-request.json index 7dc036ee1d4..5842a7b006f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-auction-generic-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-auction-generic-request.json @@ -45,15 +45,15 @@ "sdk": { "renderers": [ { - "name":"PrebidRenderer", - "version":"2.1.1", + "name": "PrebidRenderer", + "version": "2.1.1", "data": { "someData": "someData" } }, { - "name":"SampleRenderer", - "version":"1.0.0", + "name": "SampleRenderer", + "version": "1.0.0", "url": "rendererUrl" } ] diff --git a/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-cache-generic-request.json b/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-cache-generic-request.json index aa611ad083c..29a664e391c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-cache-generic-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-cache-generic-request.json @@ -13,14 +13,17 @@ "w": 300, "h": 250, "ext": { - "dsa" : { - "behalf" : "Advertiser", - "paid" : "Advertiser", - "transparency" : { - "domain" : "dsp1domain.com", - "dsaparams" : [ 1, 2 ] + "dsa": { + "behalf": "Advertiser", + "paid": "Advertiser", + "transparency": { + "domain": "dsp1domain.com", + "dsaparams": [ + 1, + 2 + ] }, - "adrender" : 1 + "adrender": 1 }, "prebid": { "type": "video", @@ -38,7 +41,7 @@ } }, "aid": "tid", - "ttlseconds" : 1500 + "ttlseconds": 1500 } ] } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-generic-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-generic-bid-request.json index 0bd20956798..2eefc3820bd 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-generic-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/generic_core_functionality/test-generic-bid-request.json @@ -1,57 +1,65 @@ { - "id" : "tid", - "imp" : [ { - "id": "impId001", - "video": { - "placement": 1, - "mimes": [ - "mimes" - ], - "w": 300, - "h": 250 - }, - "pmp": { - "deals": [ - { - "id": "dealId" - } - ] - }, - "secure": 1, - "ext": { - "tid": "${json-unit.any-string}", - "bidder": { - "accountId": 2001, - "siteId": 3001, - "zoneId": 4001 + "id": "tid", + "imp": [ + { + "id": "impId001", + "video": { + "placement": 1, + "mimes": [ + "mimes" + ], + "w": 300, + "h": 250 }, - "someExt": "someExt" + "pmp": { + "deals": [ + { + "id": "dealId" + } + ] + }, + "secure": 1, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "accountId": 2001, + "siteId": 3001, + "zoneId": 4001 + }, + "someExt": "someExt" + } } - } ], - "site" : { - "domain" : "www.example.com", - "page" : "http://www.example.com", - "publisher" : { - "domain" : "example.com" + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" }, - "ext" : { - "amp" : 0 + "ext": { + "amp": 0 } }, - "device" : { - "ua" : "testUa", - "ip" : "193.168.244.1" + "device": { + "ua": "testUa", + "ip": "193.168.244.1" }, - "at" : 1, - "tmax" : "${json-unit.any-number}", - "cur" : [ "USD" ], - "source" : { - "tid" : "${json-unit.any-string}" + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" }, - "regs" : { - "gpp_sid" : [ 1, 3, 7 ], - "ext" : { - "gdpr" : 0, + "regs": { + "gpp_sid": [ + 1, + 3, + 7 + ], + "ext": { + "gdpr": 0, "dsa": { "dsarequired": 1, "pubrender": 0, @@ -74,46 +82,48 @@ } } }, - "ext" : { - "prebid" : { - "bidadjustmentfactors" : { - "mediatypes" : { - "video" : { - "generic" : 0.9 + "ext": { + "prebid": { + "bidadjustmentfactors": { + "mediatypes": { + "video": { + "generic": 0.9 } } }, - "targeting" : { - "pricegranularity" : { - "precision" : 2, - "ranges" : [ { - "max" : 20, - "increment" : 0.1 - } ] + "targeting": { + "pricegranularity": { + "precision": 2, + "ranges": [ + { + "max": 20, + "increment": 0.1 + } + ] }, - "includewinners" : true, - "includebidderkeys" : true + "includewinners": true, + "includebidderkeys": true }, - "auctiontimestamp" : 0, - "server" : { - "externalurl" : "http://localhost:8080", - "gvlid" : 1, - "datacenter" : "local", + "auctiontimestamp": 0, + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", "http_method": "POST", "endpoint": "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/openrtb2/auction" }, "sdk": { "renderers": [ { - "name":"PrebidRenderer", - "version":"2.1.1", + "name": "PrebidRenderer", + "version": "2.1.1", "data": { "someData": "someData" } }, { - "name":"SampleRenderer", - "version":"1.0.0", + "name": "SampleRenderer", + "version": "1.0.0", "url": "rendererUrl" } ] diff --git a/src/test/resources/org/prebid/server/it/openrtb2/globalsun/test-globalsun-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/globalsun/test-globalsun-bid-request.json index d3848f87820..9fd295cb7d6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/globalsun/test-globalsun-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/globalsun/test-globalsun-bid-request.json @@ -13,7 +13,7 @@ }, "ext": { "bidder": { - "type" : "publisher", + "type": "publisher", "placementId": "test" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/grid/test-grid-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/grid/test-grid-bid-request.json index 017bd89aa3d..70d1129e09c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/grid/test-grid-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/grid/test-grid-bid-request.json @@ -20,7 +20,10 @@ }, "gpid": "some_slot", "skadn": { - "versions": [ "2.0", "2.1" ], + "versions": [ + "2.0", + "2.1" + ], "sourceapp": "880047117" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_eu_endpoint/test-huaweiads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_eu_endpoint/test-huaweiads-bid-request.json index 72ddba10eff..2107093f437 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_eu_endpoint/test-huaweiads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_eu_endpoint/test-huaweiads-bid-request.json @@ -27,7 +27,7 @@ "oaid": "oaid", "os": "android", "type": 4, - "ip" : "193.168.244.1", + "ip": "193.168.244.1", "localeCountry": "PT", "pxratio": 23.01, "width": 1080, @@ -43,7 +43,7 @@ }, "network": { "type": 0, - "cellInfo" : [ ] + "cellInfo": [] }, "regs": { "coppa": 0 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_mccmnc/test-huaweiads-auction-response.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_mccmnc/test-huaweiads-auction-response.json index 760903a05d1..04a3eaf556b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_mccmnc/test-huaweiads-auction-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_mccmnc/test-huaweiads-auction-response.json @@ -35,7 +35,7 @@ "exp": 300, "price": 0.404, "w": 300, - "nurl":"" + "nurl": "" } ], "group": 0, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_mccmnc/test-huaweiads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_mccmnc/test-huaweiads-bid-request.json index 292048557ee..e07e41a5b15 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_mccmnc/test-huaweiads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_mccmnc/test-huaweiads-bid-request.json @@ -34,7 +34,7 @@ "version": "29", "maker": "HUAWEI", "belongCountry": "ZA", - "ip" : "193.168.244.1" + "ip": "193.168.244.1" }, "geo": { }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-auction-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-auction-request.json index 28864639cae..97e3d7d3df2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-auction-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-auction-request.json @@ -70,6 +70,5 @@ } }, "ext": { - } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-auction-response.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-auction-response.json index 760903a05d1..04a3eaf556b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-auction-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-auction-response.json @@ -35,7 +35,7 @@ "exp": 300, "price": 0.404, "w": 300, - "nurl":"" + "nurl": "" } ], "group": 0, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-bid-request.json index 2240bc6e8fa..fd05cf04a8b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_non_integer_mccmnc/test-huaweiads-bid-request.json @@ -34,7 +34,7 @@ "version": "29", "maker": "HUAWEI", "belongCountry": "ZA", - "ip" : "193.168.244.1" + "ip": "193.168.244.1" }, "geo": { }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_not_app_promotion_type/test-huaweiads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_not_app_promotion_type/test-huaweiads-bid-request.json index 9f03abfd38b..addfd96f93a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_not_app_promotion_type/test-huaweiads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_not_app_promotion_type/test-huaweiads-bid-request.json @@ -42,7 +42,7 @@ "geo": { }, "network": { - "cellInfo" : [ ], + "cellInfo": [], "type": 0 }, "regs": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_ru_endpoint/test-huaweiads-auction-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_ru_endpoint/test-huaweiads-auction-request.json index 5b2f0f4b6da..01ef9226180 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_ru_endpoint/test-huaweiads-auction-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_ru_endpoint/test-huaweiads-auction-request.json @@ -70,6 +70,5 @@ } }, "ext": { - } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_ru_endpoint/test-huaweiads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_ru_endpoint/test-huaweiads-bid-request.json index 59ae554eae6..c62842632d7 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_ru_endpoint/test-huaweiads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_ru_endpoint/test-huaweiads-bid-request.json @@ -34,7 +34,7 @@ "version": "29", "maker": "HUAWEI", "belongCountry": "RU", - "ip" : "193.168.244.1" + "ip": "193.168.244.1" }, "geo": { }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_with_user_geo/test-huaweiads-auction-response.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_with_user_geo/test-huaweiads-auction-response.json index 760903a05d1..04a3eaf556b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_with_user_geo/test-huaweiads-auction-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_with_user_geo/test-huaweiads-auction-response.json @@ -35,7 +35,7 @@ "exp": 300, "price": 0.404, "w": 300, - "nurl":"" + "nurl": "" } ], "group": 0, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_with_user_geo/test-huaweiads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_with_user_geo/test-huaweiads-bid-request.json index 1c048abc1b9..3187819b1c0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_with_user_geo/test-huaweiads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_with_user_geo/test-huaweiads-bid-request.json @@ -34,7 +34,7 @@ "version": "29", "maker": "HUAWEI", "belongCountry": "ZA", - "ip" : "193.168.244.1" + "ip": "193.168.244.1" }, "network": { "carrier": 99, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_without_device_geo/test-huaweiads-auction-response.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_without_device_geo/test-huaweiads-auction-response.json index 760903a05d1..04a3eaf556b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_without_device_geo/test-huaweiads-auction-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_without_device_geo/test-huaweiads-auction-response.json @@ -35,7 +35,7 @@ "exp": 300, "price": 0.404, "w": 300, - "nurl":"" + "nurl": "" } ], "group": 0, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_without_userext/test-huaweiads-auction-response.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_without_userext/test-huaweiads-auction-response.json index 2adeb193b23..75796bc960d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_without_userext/test-huaweiads-auction-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_without_userext/test-huaweiads-auction-response.json @@ -35,7 +35,7 @@ "exp": 300, "price": 0.404, "w": 250, - "nurl":"" + "nurl": "" } ], "group": 0, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_wrong_mccmnc/test-huaweiads-auction-response.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_wrong_mccmnc/test-huaweiads-auction-response.json index 760903a05d1..04a3eaf556b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_wrong_mccmnc/test-huaweiads-auction-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_wrong_mccmnc/test-huaweiads-auction-response.json @@ -35,7 +35,7 @@ "exp": 300, "price": 0.404, "w": 300, - "nurl":"" + "nurl": "" } ], "group": 0, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_wrong_mccmnc/test-huaweiads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_wrong_mccmnc/test-huaweiads-bid-request.json index 56ff600ac2f..fb3d220299a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_wrong_mccmnc/test-huaweiads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/banner_wrong_mccmnc/test-huaweiads-bid-request.json @@ -34,7 +34,7 @@ "version": "29", "maker": "HUAWEI", "belongCountry": "ZA", - "ip" : "193.168.244.1" + "ip": "193.168.244.1" }, "geo": { }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/native_three_image/test-huaweiads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/native_three_image/test-huaweiads-bid-request.json index ffb014ca884..9d0ac31c12c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/native_three_image/test-huaweiads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/native_three_image/test-huaweiads-bid-request.json @@ -11,7 +11,9 @@ "adtype": 3, "slotid": "u42ohmaufh", "detailedCreativeTypeList": [ - "901", "904", "905" + "901", + "904", + "905" ], "format": [], "test": 1 @@ -39,7 +41,7 @@ }, "network": { "type": 0, - "cellInfo" : [ ] + "cellInfo": [] }, "regs": { }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/video_rewarded_type_with_icon/test-huaweiads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/video_rewarded_type_with_icon/test-huaweiads-bid-request.json index 6d650c57bf4..8c189de45ab 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/video_rewarded_type_with_icon/test-huaweiads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/huaweiads/video_rewarded_type_with_icon/test-huaweiads-bid-request.json @@ -37,7 +37,7 @@ }, "network": { "type": 0, - "cellInfo" : [ ] + "cellInfo": [] }, "regs": { }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-insticator-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-insticator-bid-request.json index 514878f3936..89e311b6e3c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-insticator-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-insticator-bid-request.json @@ -24,7 +24,7 @@ "page": "http://www.example.com", "publisher": { "domain": "example.com", - "id" : "adUnitId" + "id": "adUnitId" }, "ext": { "amp": 0 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/invibes/test-invibes-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/invibes/test-invibes-bid-request.json index 08e268ea7d1..b2a8b2eb3a6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/invibes/test-invibes-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/invibes/test-invibes-bid-request.json @@ -3,7 +3,7 @@ "Location": "http://www.example.com", "Lid": "", "IsTestBid": false, - "IsAMP" : false, + "IsAMP": false, "GdprConsent": "", "Gdpr": false, "InvibBVLog": false, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/kargo/test-kargo-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/kargo/test-kargo-bid-request.json index 07e5d885786..0343d04e747 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/kargo/test-kargo-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/kargo/test-kargo-bid-request.json @@ -38,8 +38,8 @@ "cur": [ "USD" ], - "regs" : { - "gdpr" : 0 + "regs": { + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/kiviads/test-kiviads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/kiviads/test-kiviads-bid-request.json index 9bc0c815069..adaedbb69f6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/kiviads/test-kiviads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/kiviads/test-kiviads-bid-request.json @@ -13,7 +13,7 @@ }, "ext": { "bidder": { - "type" : "network", + "type": "network", "endpointId": "test" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/kuantyx/test-auction-kuantyx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/kuantyx/test-auction-kuantyx-request.json index 013558bc3d8..a88a84fe78a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/kuantyx/test-auction-kuantyx-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/kuantyx/test-auction-kuantyx-request.json @@ -9,7 +9,7 @@ }, "ext": { "kuantyx": { - "zone" : 1 + "zone": 1 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/kuantyx/test-kuantyx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/kuantyx/test-kuantyx-bid-request.json index 7df0474d049..9699b58402d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/kuantyx/test-kuantyx-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/kuantyx/test-kuantyx-bid-request.json @@ -10,8 +10,8 @@ }, "ext": { "tid": "${json-unit.any-string}", - "bidder" : { - "zone" : 1 + "bidder": { + "zone": 1 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/liftoff/test-liftoff-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/liftoff/test-liftoff-bid-request.json index baf7dab5ad2..9348868846c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/liftoff/test-liftoff-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/liftoff/test-liftoff-bid-request.json @@ -3,7 +3,7 @@ "imp": [ { "id": "imp_id", - "tagid" : "placement_reference_id", + "tagid": "placement_reference_id", "secure": 1, "video": { "mimes": [ @@ -13,14 +13,14 @@ "h": 600 }, "ext": { - "bidder" : { - "bid_token" : "bid_token", - "app_store_id" : "app_store_id", - "placement_reference_id" : "placement_reference_id" + "bidder": { + "bid_token": "bid_token", + "app_store_id": "app_store_id", + "placement_reference_id": "placement_reference_id" }, - "vungle" : { - "app_store_id" : "app_store_id", - "placement_reference_id" : "placement_reference_id" + "vungle": { + "app_store_id": "app_store_id", + "placement_reference_id": "placement_reference_id" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/loyal/test-loyal-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/loyal/test-loyal-bid-request.json index c65dbcf9d26..3f7a5e60358 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/loyal/test-loyal-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/loyal/test-loyal-bid-request.json @@ -32,9 +32,11 @@ }, "at": 1, "tmax": "${json-unit.any-number}", - "cur": ["USD"], - "source" : { - "tid" : "${json-unit.any-string}" + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" }, "regs": { "ext": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mabidder/test-auction-mabidder-request.json b/src/test/resources/org/prebid/server/it/openrtb2/mabidder/test-auction-mabidder-request.json index 79a8207be87..de8cce2a179 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/mabidder/test-auction-mabidder-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/mabidder/test-auction-mabidder-request.json @@ -4,7 +4,7 @@ "bundle": "com.prebid" }, "device": { - "ifa":"87857b31-8942-4646-ae80-ab9c95bf3fab" + "ifa": "87857b31-8942-4646-ae80-ab9c95bf3fab" }, "imp": [ { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/madsense/test-madsense-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/madsense/test-madsense-bid-request.json index 87da2e9c666..defd91e64e4 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/madsense/test-madsense-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/madsense/test-madsense-bid-request.json @@ -22,8 +22,8 @@ "site": { "domain": "www.example.com", "page": "http://www.example.com", - "publisher" : { - "domain" : "example.com" + "publisher": { + "domain": "example.com" }, "ext": { "amp": 0 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/medianet/test-medianet-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/medianet/test-medianet-bid-response.json index 916e703c412..878f8d9c940 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/medianet/test-medianet-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/medianet/test-medianet-bid-response.json @@ -1,4 +1,4 @@ - { +{ "id": "tid", "seatbid": [ { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-request.json b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-request.json index cacda5b188c..89c82b49442 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-request.json @@ -11,7 +11,7 @@ "missena": { "apiKey": "apiKey", "placement": "placement", - "test": "test" + "sample": "sample" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-response.json b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-response.json index 344c58cb6e6..4b0511cc829 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-auction-missena-response.json @@ -10,6 +10,8 @@ "price": 10.2, "adm": "adm", "crid": "id", + "w": 320, + "h": 250, "ext": { "origbidcpm": 10.2, "origbidcur": "USD", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-request.json index 2feeee36d73..f5adf2e85c1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-request.json @@ -5,8 +5,9 @@ "request_id": "request_id", "timeout": "${json-unit.any-number}", "params": { + "apiKey": "apiKey", "placement": "placement", - "test": "test" + "sample": "sample" }, "ortb2": { "id": "request_id", @@ -23,7 +24,7 @@ "bidder": { "apiKey": "apiKey", "placement": "placement", - "test": "test" + "sample": "sample" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-response.json index 4dece3dba9b..1c4c0cbfacd 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/missena/test-missena-bid-response.json @@ -2,5 +2,7 @@ "requestId": "id", "cpm": 10.2, "ad": "adm", - "currency": "USD" + "currency": "USD", + "width": 320, + "height": 250 } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobilefuse/test-mobilefuse-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/mobilefuse/test-mobilefuse-bid-request.json index 2bd99eaa080..0cb00eb6a2d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/mobilefuse/test-mobilefuse-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/mobilefuse/test-mobilefuse-bid-request.json @@ -33,8 +33,8 @@ "cur": [ "USD" ], - "regs" : { - "gdpr" : 0 + "regs": { + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mobkoi/test-mobkoi-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/mobkoi/test-mobkoi-bid-request.json index dbfe0d174e4..aa8de86d195 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/mobkoi/test-mobkoi-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/mobkoi/test-mobkoi-bid-request.json @@ -7,10 +7,10 @@ "w": 300, "h": 250 }, - "tagid" : "999999", + "tagid": "999999", "secure": 1, "ext": { - "tid" :"${json-unit.any-string}", + "tid": "${json-unit.any-string}", "bidder": { "placementId": "999999" } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/msft/test-msft-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/msft/test-msft-bid-request.json index 9c353842eb8..dacde777688 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/msft/test-msft-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/msft/test-msft-bid-request.json @@ -48,7 +48,7 @@ "externalurl": "http://localhost:8080", "gvlid": 1, "datacenter": "local", - "http_method" : "POST", + "http_method": "POST", "endpoint": "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/openrtb2/auction" } }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/multi_bid/test-auction-generic-genericAlias-request.json b/src/test/resources/org/prebid/server/it/openrtb2/multi_bid/test-auction-generic-genericAlias-request.json index 12a3381bff4..86a76b22fe9 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/multi_bid/test-auction-generic-genericAlias-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/multi_bid/test-auction-generic-genericAlias-request.json @@ -28,7 +28,7 @@ "genericProperty": 1 }, "genericAlias": { - "genericAliasProperty" : 2 + "genericAliasProperty": 2 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/nativery/test-auction-nativery-response.json b/src/test/resources/org/prebid/server/it/openrtb2/nativery/test-auction-nativery-response.json index 97b4616fe92..3b38c54c6e2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/nativery/test-auction-nativery-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/nativery/test-auction-nativery-response.json @@ -9,7 +9,9 @@ "exp": 300, "price": 3.33, "adm": "
ad
", - "adomain": ["example.com"], + "adomain": [ + "example.com" + ], "crid": "creativeId", "mtype": 1, "ext": { @@ -20,7 +22,9 @@ "meta": { "adaptercode": "nativery", "mediaType": "banner", - "advertiserDomains": ["example.com"] + "advertiserDomains": [ + "example.com" + ] } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/nextmillennium/test-auction-nextmillennium-request.json b/src/test/resources/org/prebid/server/it/openrtb2/nextmillennium/test-auction-nextmillennium-request.json index 989d0611c29..497962532d1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/nextmillennium/test-auction-nextmillennium-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/nextmillennium/test-auction-nextmillennium-request.json @@ -8,10 +8,16 @@ "h": 250 }, "ext": { - "nextmillennium" : { + "nextmillennium": { "placement_id": "placement_id", - "adSlots": ["slot-1", "slot-2"], - "allowedAds": ["banner", "native"] + "adSlots": [ + "slot-1", + "slot-2" + ], + "allowedAds": [ + "banner", + "native" + ] } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/nextmillennium/test-nextmillennium-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/nextmillennium/test-nextmillennium-bid-request.json index 6db9efc19f4..f37484299b5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/nextmillennium/test-nextmillennium-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/nextmillennium/test-nextmillennium-bid-request.json @@ -9,8 +9,10 @@ }, "secure": 1, "ext": { - "nextMillennium" : { - "nmmFlags" : [ "1" ] + "nextMillennium": { + "nmmFlags": [ + "1" + ] }, "prebid": { "storedrequest": { @@ -61,9 +63,17 @@ } }, "nextMillennium": { - "nmmFlags": [ "1" ], - "adSlots": ["slot-1", "slot-2"], - "allowedAds": ["banner", "native"], + "nmmFlags": [ + "1" + ], + "adSlots": [ + "slot-1", + "slot-2" + ], + "allowedAds": [ + "banner", + "native" + ], "nm_version": "v1.0.1", "server_version": "${json-unit.any-string}" } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ogury/test-auction-ogury-request.json b/src/test/resources/org/prebid/server/it/openrtb2/ogury/test-auction-ogury-request.json index 6fbe8ffd455..856ee349718 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ogury/test-auction-ogury-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ogury/test-auction-ogury-request.json @@ -3,7 +3,7 @@ "imp": [ { "id": "imp_id", - "bidfloorcur" : "USD", + "bidfloorcur": "USD", "banner": { "w": 300, "h": 250 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/omnidex/test-omnidex-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/omnidex/test-omnidex-bid-request.json index dd094df0cd6..4a405f2e47a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/omnidex/test-omnidex-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/omnidex/test-omnidex-bid-request.json @@ -39,7 +39,7 @@ "USD" ], "regs": { - "gdpr": 0 + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request.json index d7f4efb8bef..cf41e868679 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request.json @@ -18,7 +18,7 @@ "bar2" ] }, - "tid" : "${json-unit.any-string}" + "tid": "${json-unit.any-string}" } } ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/outbrain/test-outbrain-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/outbrain/test-outbrain-bid-request.json index f64a808f06b..8cb23fa0c8d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/outbrain/test-outbrain-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/outbrain/test-outbrain-bid-request.json @@ -32,10 +32,10 @@ "tid": "${json-unit.any-string}" }, "site": { - "domain" : "www.example.com", + "domain": "www.example.com", "page": "http://www.example.com", "publisher": { - "id" : "extPubId", + "id": "extPubId", "name": "extPubName", "domain": "extPubDomain" }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ownadx/test-ownadx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/ownadx/test-ownadx-bid-request.json index 72bf7efff52..29a71b948d0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ownadx/test-ownadx-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ownadx/test-ownadx-bid-request.json @@ -12,8 +12,8 @@ "tid": "${json-unit.any-string}", "bidder": { "tokenId": "testTokenId", - "seatId" : "testSeatId", - "sspId" : "testSspId" + "seatId": "testSeatId", + "sspId": "testSspId" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ownadx/test-ownadx-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/ownadx/test-ownadx-bid-response.json index 9eef9d710d7..46c1f743f04 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ownadx/test-ownadx-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ownadx/test-ownadx-bid-response.json @@ -5,7 +5,7 @@ "bid": [ { "id": "bid_id", - "mtype" : 1, + "mtype": 1, "impid": "imp_id", "price": 3.33, "adid": "adid001", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pgamssp/test-pgamssp-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/pgamssp/test-pgamssp-bid-request.json index 05195e65132..a1ec2c35084 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pgamssp/test-pgamssp-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pgamssp/test-pgamssp-bid-request.json @@ -8,10 +8,10 @@ "w": 320, "h": 250 }, - "ext" : { - "bidder" : { - "type" : "publisher", - "placementId" : "placementid" + "ext": { + "bidder": { + "type": "publisher", + "placementId": "placementid" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request-params-as-string.json b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request-params-as-string.json index 0d71537971e..49c030d8f37 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request-params-as-string.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request-params-as-string.json @@ -8,7 +8,7 @@ "w": 300, "h": 600 }, - "tagid" : "456", + "tagid": "456", "ext": { "tid": "${json-unit.any-string}", "bidder": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request.json index df2d0e91d8b..078d475b13c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request.json @@ -8,7 +8,7 @@ "w": 300, "h": 600 }, - "tagid" : "456", + "tagid": "456", "ext": { "tid": "${json-unit.any-string}", "bidder": { @@ -41,8 +41,8 @@ "cur": [ "USD" ], - "regs" : { - "gdpr" : 0 + "regs": { + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/readpeak/test-readpeak-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/readpeak/test-readpeak-bid-request.json index c3f30e0d872..348984beb1a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/readpeak/test-readpeak-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/readpeak/test-readpeak-bid-request.json @@ -7,8 +7,8 @@ "w": 300, "h": 250 }, - "tagid" : "tag-id-b", - "bidfloor" : 5, + "tagid": "tag-id-b", + "bidfloor": 5, "secure": 1, "ext": { "tid": "${json-unit.any-string}", @@ -22,7 +22,7 @@ } ], "site": { - "id" : "site-id-b", + "id": "site-id-b", "domain": "www.example.com", "page": "http://www.example.com", "publisher": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rediads/test-rediads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/rediads/test-rediads-bid-request.json index c7e89611929..e79e6908dae 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rediads/test-rediads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rediads/test-rediads-bid-request.json @@ -18,7 +18,7 @@ "page": "http://www.example.com", "publisher": { "id": "publisherId", - "domain" : "example.com" + "domain": "example.com" }, "ext": { "amp": 0 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/relevantdigital/test-relevantdigital-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/relevantdigital/test-relevantdigital-bid-request.json index 9321701ea0b..301bb6b97e5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/relevantdigital/test-relevantdigital-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/relevantdigital/test-relevantdigital-bid-request.json @@ -25,14 +25,14 @@ } } ], - "site" : { - "domain" : "www.example.com", - "page" : "http://www.example.com", - "publisher" : { - "domain" : "example.com" + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" }, - "ext" : { - "amp" : 0 + "ext": { + "amp": 0 } }, "source": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/richaudience/test-auction-richaudience-request.json b/src/test/resources/org/prebid/server/it/openrtb2/richaudience/test-auction-richaudience-request.json index 7643ba7409b..26f3e8612a1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/richaudience/test-auction-richaudience-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/richaudience/test-auction-richaudience-request.json @@ -7,7 +7,7 @@ "w": 300, "h": 250 }, - "tagid" : "some_tag_id", + "tagid": "some_tag_id", "ext": { "richaudience": { "pid": "some_pid", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/richaudience/test-richaudience-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/richaudience/test-richaudience-bid-request.json index 522f166abe1..68856dea69d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/richaudience/test-richaudience-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/richaudience/test-richaudience-bid-request.json @@ -29,7 +29,7 @@ "publisher": { "domain": "example.com" }, - "keywords" : "tagId=some_tag_id", + "keywords": "tagId=some_tag_id", "ext": { "amp": 0 } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-auction-scalibur-request.json b/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-auction-scalibur-request.json new file mode 100644 index 00000000000..2435fe56373 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-auction-scalibur-request.json @@ -0,0 +1,25 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 320, + "h": 250 + }, + "bidfloorcur": "USD", + "ext": { + "scalibur": { + "placementId": "placement_id", + "extraField": "extra_field" + } + } + } + ], + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-auction-scalibur-response.json b/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-auction-scalibur-response.json new file mode 100644 index 00000000000..37da829cd13 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-auction-scalibur-response.json @@ -0,0 +1,41 @@ +{ + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "exp": 300, + "price": 0.01, + "adid": "2068416", + "cid": "8048", + "crid": "24080", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "scalibur" + } + }, + "origbidcpm": 0.01, + "origbidcur": "USD" + } + } + ], + "seat": "scalibur", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "scalibur": "{{ scalibur.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 0 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-scalibur-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-scalibur-bid-request.json new file mode 100644 index 00000000000..cafa774cea7 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-scalibur-bid-request.json @@ -0,0 +1,40 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 320, + "h": 250 + }, + "tagid": "placement_id", + "bidfloorcur": "USD", + "secure": 1, + "ext": { + "extraField": "extra_field" + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "source": { + "tid": "${json-unit.any-string}" + }, + "regs": { + "gdpr": 0 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-scalibur-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-scalibur-bid-response.json new file mode 100644 index 00000000000..47d4f8718ea --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/scalibur/test-scalibur-bid-response.json @@ -0,0 +1,19 @@ +{ + "id": "tid", + "seatbid": [ + { + "bid": [ + { + "crid": "24080", + "adid": "2068416", + "price": 0.01, + "id": "bid_id", + "impid": "imp_id", + "cid": "8048", + "mtype": 1 + } + ], + "type": "banner" + } + ] +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/seedtag/test-auction-seedtag-response.json b/src/test/resources/org/prebid/server/it/openrtb2/seedtag/test-auction-seedtag-response.json index d95fbe5ae64..1d169d2b186 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/seedtag/test-auction-seedtag-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/seedtag/test-auction-seedtag-response.json @@ -15,11 +15,11 @@ "w": 300, "h": 250, "mtype": 1, - "ext":{ - "origbidcpm":3.33, - "origbidcur":"USD", + "ext": { + "origbidcpm": 3.33, + "origbidcur": "USD", "prebid": { - "type":"banner", + "type": "banner", "meta": { "adaptercode": "seedtag" } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-auction-sevio-request.json b/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-auction-sevio-request.json new file mode 100644 index 00000000000..c42a183e75e --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-auction-sevio-request.json @@ -0,0 +1,23 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 320, + "h": 250 + }, + "ext": { + "sevio": { + "placementId": "testPlacementId" + } + } + } + ], + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-auction-sevio-response.json b/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-auction-sevio-response.json new file mode 100644 index 00000000000..32c3ee19b64 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-auction-sevio-response.json @@ -0,0 +1,39 @@ +{ + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "exp": 300, + "price": 0.01, + "crid": "crid1", + "mtype": 1, + "ext": { + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "sevio" + } + }, + "origbidcpm": 0.01, + "origbidcur": "USD" + } + } + ], + "seat": "sevio", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "sevio": "{{ sevio.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 0 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-sevio-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-sevio-bid-request.json new file mode 100644 index 00000000000..5a21bde73d9 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-sevio-bid-request.json @@ -0,0 +1,57 @@ +{ + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "secure": 1, + "banner": { + "w": 320, + "h": 250 + }, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "placementId": "testPlacementId" + } + } + } + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "prebid": { + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", + "http_method": "POST", + "endpoint": "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/openrtb2/auction" + } + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-sevio-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-sevio-bid-response.json new file mode 100644 index 00000000000..53d65871871 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/sevio/test-sevio-bid-response.json @@ -0,0 +1,18 @@ +{ + "id": "tid", + "seatbid": [ + { + "bid": [ + { + "crid": "crid1", + "price": 0.01, + "id": "bid_id", + "impid": "imp_id", + "mtype": 1 + } + ], + "type": "banner" + } + ], + "cur": "USD" +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-sharethrough-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-sharethrough-bid-request.json index 8243a72aac4..7d8f0e772bb 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-sharethrough-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-sharethrough-bid-request.json @@ -33,7 +33,9 @@ }, "at": 1, "tmax": "${json-unit.any-number}", - "cur": ["USD"], + "cur": [ + "USD" + ], "source": { "tid": "${json-unit.any-string}", "ext": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/showheroes/test-showheroes-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/showheroes/test-showheroes-bid-request.json index 24c84321a2c..5a938a98b88 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/showheroes/test-showheroes-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/showheroes/test-showheroes-bid-request.json @@ -36,7 +36,9 @@ }, "at": 1, "tmax": "${json-unit.any-number}", - "cur": ["USD"], + "cur": [ + "USD" + ], "source": { "tid": "${json-unit.any-string}", "ext": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/showheroesBs/test-showheroes-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/showheroesBs/test-showheroes-bid-request.json index 24c84321a2c..5a938a98b88 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/showheroesBs/test-showheroes-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/showheroesBs/test-showheroes-bid-request.json @@ -36,7 +36,9 @@ }, "at": 1, "tmax": "${json-unit.any-number}", - "cur": ["USD"], + "cur": [ + "USD" + ], "source": { "tid": "${json-unit.any-string}", "ext": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/showheroes_bs/test-showheroes-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/showheroes_bs/test-showheroes-bid-request.json index 24c84321a2c..5a938a98b88 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/showheroes_bs/test-showheroes-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/showheroes_bs/test-showheroes-bid-request.json @@ -36,7 +36,9 @@ }, "at": 1, "tmax": "${json-unit.any-number}", - "cur": ["USD"], + "cur": [ + "USD" + ], "source": { "tid": "${json-unit.any-string}", "ext": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/silverpush/test-silverpush-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/silverpush/test-silverpush-bid-request.json index eddadb070cc..d2e48575ec6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/silverpush/test-silverpush-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/silverpush/test-silverpush-bid-request.json @@ -25,7 +25,7 @@ "domain": "www.example.com", "page": "http://www.example.com", "publisher": { - "id" : "testPublisherId", + "id": "testPublisherId", "domain": "example.com" }, "ext": { @@ -35,8 +35,8 @@ "device": { "ua": "userAgent", "ip": "193.168.244.1", - "devicetype" : 2, - "os" : "Unknown" + "devicetype": 2, + "os": "Unknown" }, "at": 1, "tmax": "${json-unit.any-number}", @@ -49,7 +49,7 @@ } }, "ext": { - "bc" : "sp_pb_ortb_1.0.0", - "publisherId" : "testPublisherId" + "bc": "sp_pb_ortb_1.0.0", + "publisherId": "testPublisherId" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-auction-smaato-response.json b/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-auction-smaato-response.json index 32dc7209653..9f70d8998a2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-auction-smaato-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-auction-smaato-response.json @@ -9,7 +9,6 @@ "crid": "crid", "id": "bid_id", "impid": "imp_id", - "exp": 300, "price": 0.01, "exp": 300, "ext": { @@ -21,7 +20,10 @@ }, "origbidcpm": 0.01, "format": "BANNER", - "curls": ["curl1", "curl2"] + "curls": [ + "curl1", + "curl2" + ] } } ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-smaato-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-smaato-bid-request.json index 5230998792c..53aa535933f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-smaato-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-smaato-bid-request.json @@ -10,7 +10,7 @@ "h": 250 }, "tagid": "130563103", - "ext" : { + "ext": { "gpid": 1, "skadn": { "versions": [ @@ -43,11 +43,11 @@ "source": { "tid": "${json-unit.any-string}" }, - "site" : { - "domain" : "www.example.com", - "page" : "http://www.example.com", - "publisher" : { - "id" : "11000" + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "id": "11000" } }, "device": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-smaato-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-smaato-bid-response.json index d81f59c0ca9..9fa6eea1190 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-smaato-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/smaato/test-smaato-bid-response.json @@ -12,7 +12,10 @@ "price": 0.01, "ext": { "format": "BANNER", - "curls": ["curl1", "curl2"] + "curls": [ + "curl1", + "curl2" + ] } } ] diff --git a/src/test/resources/org/prebid/server/it/openrtb2/smartx/test-smartx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/smartx/test-smartx-bid-request.json index 0c46819952e..f007af25768 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/smartx/test-smartx-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/smartx/test-smartx-bid-request.json @@ -40,8 +40,8 @@ "cur": [ "USD" ], - "regs" : { - "gdpr" : 0 + "regs": { + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-auction-sparteo-request.json b/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-auction-sparteo-request.json index b53ec1d1693..e2b9310fdf5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-auction-sparteo-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-auction-sparteo-request.json @@ -1,50 +1,50 @@ { - "id": "request-id", - "imp": [ - { - "id": "div-banner-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ], - "topframe": 1 - }, - "ext": { - "tid": "df097866-eb0e-4fc1-89c8-bb4c38ec8c2e", - "sparteo": { - "networkId": "networkId" - } - } + "id": "request-id", + "imp": [ + { + "id": "div-banner-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "topframe": 1 + }, + "ext": { + "tid": "df097866-eb0e-4fc1-89c8-bb4c38ec8c2e", + "sparteo": { + "networkId": "networkId" } - ], - "site": { - "domain": "dev.sparteo.com", - "page": "https://dev.sparteo.com/page/test/", - "ref": "https://dev.sparteo.com/page/test/", - "publisher": { - "id": "sparteo", - "domain": "dev.sparteo.com", - "ext": { - "params": { - "networkId": "networkId" - } - } - }, - "ext": { - "amp": 0 + } + } + ], + "site": { + "domain": "dev.sparteo.com", + "page": "https://dev.sparteo.com/page/test/", + "ref": "https://dev.sparteo.com/page/test/", + "publisher": { + "id": "sparteo", + "domain": "dev.sparteo.com", + "ext": { + "params": { + "networkId": "networkId" } + } }, - "device": { - "ua": "userAgent", - "ip": "193.168.244.1" - }, - "tmax": 5000, - "regs": { - "ext": { - "gdpr": 0 - } + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 } -} \ No newline at end of file + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-auction-sparteo-response.json b/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-auction-sparteo-response.json index b6876245848..55e025ce82b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-auction-sparteo-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-auction-sparteo-response.json @@ -1,46 +1,46 @@ { - "id": "request-id", - "seatbid": [ + "id": "request-id", + "seatbid": [ + { + "seat": "sparteo", + "group": 0, + "bid": [ { - "seat": "sparteo", - "group": 0, - "bid": [ - { - "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", - "impid": "div-banner-id", - "price": 0.10797, - "crid": "banner_creative_test", - "mtype": 1, - "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", - "adm": "", - "adomain": [ - "dev.sparteo.com" - ], - "w": 300, - "h": 250, - "exp": 300, - "ext": { - "prebid": { - "type": "banner", - "meta": { - "adaptercode": "sparteo" - } - }, - "origbidcpm": 0.10797, - "origbidcur": "USD" - } - } - ] + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-banner-id", + "price": 0.10797, + "crid": "banner_creative_test", + "mtype": 1, + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "", + "adomain": [ + "dev.sparteo.com" + ], + "w": 300, + "h": 250, + "exp": 300, + "ext": { + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "sparteo" + } + }, + "origbidcpm": 0.10797, + "origbidcur": "USD" + } } - ], - "cur": "USD", - "ext": { - "responsetimemillis": { - "sparteo": "{{ sparteo.response_time_ms }}" - }, - "prebid": { - "auctiontimestamp": 0 - }, - "tmaxrequest": 5000 + ] } -} \ No newline at end of file + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "sparteo": "{{ sparteo.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 0 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-sparteo-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-sparteo-bid-response.json index 2b6d330c63a..24f0abaf138 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-sparteo-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sparteo/test-sparteo-bid-response.json @@ -1,28 +1,29 @@ { - "id": "request-id", - "seatbid": [ + "id": "request-id", + "seatbid": [ + { + "bid": [ { - "bid": [ - { - "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", - "impid": "div-banner-id", - "price": 0.10797, - "crid": "banner_creative_test", - "mtype": 1, - "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", - "adm": "", - "adomain": [ - "dev.sparteo.com" - ], - "w": 300, - "h": 250, - "ext": { - "prebid": { - "type": "banner" - } - } - }] + "id": "137dd2bd-3015-407a-ab50-384aa2c706d7", + "impid": "div-banner-id", + "price": 0.10797, + "crid": "banner_creative_test", + "mtype": 1, + "nurl": "https://dev.sparteo.com/event/sparteo/0a98964d-1cf9-4802-93e9-c59c18f497fa?d=kyGjrlVurDF3FlG8d7juZXMzNlGoZA06b75fJDG9dyF3LTd9LzPxLRHzMzFzMfwfdlifNfF9L7AlLzreYS96MTH9JTP7NRdtNRU4LS8lYTPwZTMlLRPyYTUfJDGjdEPfNfFvdzGzJWA8Y6Qob75fJDG8YSF3FirvJWe9rEHtY7xoZW49JzKuLSFsFmBiFgnfZCV7JmMwYXG9ZW1uY70tNgP9MRPfJDGwrSF3Fle9rEBzGTMBGTGCGTGCZCV7JmMwYXG9ZW1uY70tGTMBMRP9MDUyQmBeZ7UjLiZzZXG7ZXFtrC1td7VyrlVyJWGoZCQobldjLiZzZXG7ZXGUb8MjdmZjdiGoZCQoblrDYW4uZXFfJDGfdmFfNfFfJDGuhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGwhWPfNfGjYlY4ZTi6ZD8iMCMeJTQeLRKtNWL9YS8iLzK8LTPwMzL7ZRYfJDGib6LfNfGtYWMOUyFsFlQfFgnfrW4qbl06bfFsFmVib75fNfG8bltub6ruFfwfrWQ9FgnfZCVzh6QvdDFsFlAfrDF3WyGzd6HtY70tYl1tbW0uZXj9hXojdj0eXzUwFfwfd6MwJWMvbWGvJXB8YlZ8rEVyZV0jbXB9kV18LDFsFlrsb7GebDFsFmBfdy8fhWPtdlA9ZV0OPV1xLRHwFfwfdlV7ZW48ZV0BXzKwLDFsFlGoZD8vdEQaT6B9hW8KXzP8Fj9sFmByZWQzFgo2Flrsb7GebKxjrlVPdlVPdlViFgnxJDGobXBLZXZjbAByZVByZWPfNgKsFlMyZWAadCVyX7jtdDF3LS58MzYsFlGobCxeYlxjX6Bjdj0obXHfNgKsFlVzrCjtYXQjZA0yZXZjbmVjFgnwJgF5NSwfrljvrXMskV0yZXZjbmVadlA9hW1fNgKsFmrobj0yYXQjFgnwJgHyMSwfbWAyZ7juX6ByZWPfNgHuLRH8JDGfhWQadEGoY7UfNgHuLX9sFlGohSF3FlQorf8fYW4uZXFfJDGwbELfNjsfLzHwkRF8LDGrJDGwbXPfNjsfYlAublVyFj9sFlVsdyF3WyFzLRB5LgUwFfwfLzHwkRKwLDFsFgLwLEcxLgUfJDFzLRB5LTUwFj9sFlVtrDF3WyGfYW4uZXFfXSwfYlQzFgobFlAikW08bCjqZSFsFlAwdC4jkEVzFfwfZ6GoZDFsFl0lrC8jZCjeFfwfb74jrCAmFfwfb6BjbmcfJDGyhXMjFfwfdmVfhWMvbfFsFmMtYXG9YWQzZXG7ZXFfJDGzbWjsZXrebmQjZDFsFmVudmVskSGrJDGtYfF3ZlAsd7UsFlZ9dyF3WyGPYXMzVCeyb6VmhKZvdl8erDGrJDGydyF3LD55MSwfYlifNfFxLzriZRGfZD9zLRK8JTPwM7KtYWF8LD9zNRQeYTGgMzH7ZRdfJDGfdDF3LD5xJDGlrDF3FjBed6MUhEGvrWrnQl0ybWA9Fm9=", + "adm": "", + "adomain": [ + "dev.sparteo.com" + ], + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } } - ], - "cur": "USD" -} \ No newline at end of file + ] + } + ], + "cur": "USD" +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/startio/test-startio-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/startio/test-startio-bid-response.json index dac8b1ab26b..ad341e1f51f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/startio/test-startio-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/startio/test-startio-bid-response.json @@ -22,7 +22,7 @@ "IAB0" ], "ext": { - "prebid":{ + "prebid": { "type": "video" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-auction-stroeercore-request.json b/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-auction-stroeercore-request.json index e119f4ae0c5..f384d06f54c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-auction-stroeercore-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-auction-stroeercore-request.json @@ -16,7 +16,9 @@ { "id": "imp_id_2", "video": { - "mimes": ["video/mp4"], + "mimes": [ + "video/mp4" + ], "w": 300, "h": 250 }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-auction-stroeercore-response.json b/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-auction-stroeercore-response.json index 7df441df2c4..459c8714a9a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-auction-stroeercore-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-auction-stroeercore-response.json @@ -9,7 +9,7 @@ "exp": 300, "price": 7.713, "adm": "
foo
", - "crid":"banner_creative_id", + "crid": "banner_creative_id", "w": 300, "h": 250, "mtype": 1, @@ -30,7 +30,7 @@ "exp": 1500, "price": 6.494, "adm": "
video
", - "crid":"video_creative_id", + "crid": "video_creative_id", "mtype": 2, "ext": { "origbidcpm": 5.7, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-stroeercore-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-stroeercore-bid-request.json index 7d1204a5c70..7b3152df850 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-stroeercore-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/stroeercore/test-stroeercore-bid-request.json @@ -20,7 +20,9 @@ "id": "imp_id_2", "secure": 1, "video": { - "mimes": ["video/mp4"], + "mimes": [ + "video/mp4" + ], "w": 300, "h": 250 }, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-auction-synapsehx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-auction-synapsehx-request.json new file mode 100644 index 00000000000..840c0894a31 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-auction-synapsehx-request.json @@ -0,0 +1,23 @@ +{ + "id": "tid", + "imp": [ + { + "id": "impId001", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "synapsehx": { + "tenantId": "tenant-id-0" + } + } + } + ], + "tmax": 5000, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-auction-synapsehx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-auction-synapsehx-response.json new file mode 100644 index 00000000000..63f2c4c2974 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-auction-synapsehx-response.json @@ -0,0 +1,40 @@ +{ + "id": "tid", + "seatbid": [ + { + "bid": [ + { + "id": "bid001", + "impid": "impId001", + "price": 3.33, + "crid": "crid001", + "w": 300, + "h": 250, + "exp": 300, + "mtype": 1, + "ext": { + "prebid": { + "type": "banner", + "meta": { + "adaptercode": "synapsehx" + } + }, + "origbidcpm": 3.33 + } + } + ], + "seat": "synapsehx", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "synapsehx": "{{ synapsehx.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-synapsehx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-synapsehx-bid-request.json new file mode 100644 index 00000000000..6797cec5a5f --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-synapsehx-bid-request.json @@ -0,0 +1,57 @@ +{ + "id": "tid", + "imp": [ + { + "id": "impId001", + "banner": { + "w": 300, + "h": 250 + }, + "secure": 1, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "tenantId": "tenant-id-0" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "prebid": { + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", + "http_method": "POST", + "endpoint": "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/openrtb2/auction" + } + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-synapsehx-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-synapsehx-bid-response.json new file mode 100644 index 00000000000..72cab5f0364 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/synapsehx/test-synapsehx-bid-response.json @@ -0,0 +1,18 @@ +{ + "id": "tid", + "seatbid": [ + { + "bid": [ + { + "id": "bid001", + "impid": "impId001", + "price": 3.33, + "crid": "crid001", + "h": 250, + "w": 300, + "mtype": 1 + } + ] + } + ] +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-auction-taboola-request.json b/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-auction-taboola-request.json index 55b4cebe6cc..5f4ae8d98f9 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-auction-taboola-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-auction-taboola-request.json @@ -11,7 +11,7 @@ "taboola": { "publisherId": "publisher-id", "tagid": "tag-id", - "bidfloor" : 20, + "bidfloor": 20, "publisherDomain": "http://domain.com" } } @@ -26,7 +26,7 @@ "taboola": { "publisherId": "publisher-id", "tagid": "tag-id", - "bidfloor" : 20, + "bidfloor": 20, "publisherDomain": "http://domain.com" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-taboola-bid-request-banner.json b/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-taboola-bid-request-banner.json index 003c2e6d99f..8439ca28847 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-taboola-bid-request-banner.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-taboola-bid-request-banner.json @@ -8,14 +8,14 @@ "w": 300, "h": 250 }, - "tagid" : "tag-id", + "tagid": "tag-id", "bidfloor": 20, "ext": { - "tid" : "${json-unit.any-string}", + "tid": "${json-unit.any-string}", "bidder": { "publisherId": "publisher-id", "tagid": "tag-id", - "bidfloor" : 20, + "bidfloor": 20, "publisherDomain": "http://domain.com" } } @@ -25,12 +25,12 @@ "tid": "${json-unit.any-string}" }, "site": { - "id" : "publisher-id", - "name" : "publisher-id", + "id": "publisher-id", + "name": "publisher-id", "domain": "http://domain.com", "page": "http://www.example.com", "publisher": { - "id" : "publisher-id" + "id": "publisher-id" }, "ext": { "amp": 0 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-taboola-bid-request-native.json b/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-taboola-bid-request-native.json index 4b25435e4d6..936192628af 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-taboola-bid-request-native.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/taboola/test-taboola-bid-request-native.json @@ -8,14 +8,14 @@ "request": "{\"ver\":\"1.2\",\"context\":1,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":2,\"required\":1,\"title\":{\"len\":90}},{\"id\":6,\"required\":1,\"img\":{\"type\":3,\"wmin\":128,\"hmin\":128,\"mimes\":[\"image/jpg\",\"image/jpeg\",\"image/png\"]}},{\"id\":7,\"required\":1,\"data\":{\"type\":2,\"len\":120}}]}", "ver": "1.2" }, - "tagid" : "tag-id", + "tagid": "tag-id", "bidfloor": 20, "ext": { - "tid" : "${json-unit.any-string}", + "tid": "${json-unit.any-string}", "bidder": { "publisherId": "publisher-id", "tagid": "tag-id", - "bidfloor" : 20, + "bidfloor": 20, "publisherDomain": "http://domain.com" } } @@ -25,12 +25,12 @@ "tid": "${json-unit.any-string}" }, "site": { - "id" : "publisher-id", - "name" : "publisher-id", + "id": "publisher-id", + "name": "publisher-id", "domain": "http://domain.com", "page": "http://www.example.com", "publisher": { - "id" : "publisher-id" + "id": "publisher-id" }, "ext": { "amp": 0 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/tagoras/test-tagoras-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/tagoras/test-tagoras-bid-request.json index dd094df0cd6..4a405f2e47a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/tagoras/test-tagoras-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/tagoras/test-tagoras-bid-request.json @@ -39,7 +39,7 @@ "USD" ], "regs": { - "gdpr": 0 + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/teads/test-teads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/teads/test-teads-bid-request.json index d95db142a43..35773194d48 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/teads/test-teads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/teads/test-teads-bid-request.json @@ -8,7 +8,7 @@ "w": 300, "h": 250 }, - "secure" : 1, + "secure": 1, "ext": { "kv": { "placementId": 125 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/theadx/test-auction-theadx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/theadx/test-auction-theadx-request.json index a4243b06de6..3e5ac0eb358 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/theadx/test-auction-theadx-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/theadx/test-auction-theadx-request.json @@ -9,7 +9,7 @@ }, "ext": { "theadx": { - "tagid" : "123" + "tagid": "123" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/theadx/test-theadx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/theadx/test-theadx-bid-request.json index bebc09c1320..d7848781e7d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/theadx/test-theadx-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/theadx/test-theadx-bid-request.json @@ -11,8 +11,8 @@ "tagid": "123", "ext": { "tid": "${json-unit.any-string}", - "bidder" : { - "tagid" : "123" + "bidder": { + "tagid": "123" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/thetradedesk/test-auction-thetradedesk-request.json b/src/test/resources/org/prebid/server/it/openrtb2/thetradedesk/test-auction-thetradedesk-request.json index e3fba9cb248..8f944980ed1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/thetradedesk/test-auction-thetradedesk-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/thetradedesk/test-auction-thetradedesk-request.json @@ -17,8 +17,6 @@ ], "tmax": 5000, "regs": { - "ext": { - "gdpr": 0 - } + "gdpr": 0 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/thetradedesk/test-thetradedesk-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/thetradedesk/test-thetradedesk-bid-request.json index 29e68d04d41..1fe5f17aa02 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/thetradedesk/test-thetradedesk-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/thetradedesk/test-thetradedesk-bid-request.json @@ -41,9 +41,7 @@ "USD" ], "regs": { - "ext": { - "gdpr": 0 - } + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/trustedstack/test-trustedstack-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/trustedstack/test-trustedstack-bid-response.json index 2943d394d9b..4479b85ad88 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/trustedstack/test-trustedstack-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/trustedstack/test-trustedstack-bid-response.json @@ -1,4 +1,4 @@ - { +{ "id": "tid", "seatbid": [ { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/trustx/test-auction-trustx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/trustx/test-auction-trustx-response.json index c721e26850a..d660f595fe1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/trustx/test-auction-trustx-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/trustx/test-auction-trustx-response.json @@ -19,9 +19,9 @@ "networkName": "test-network" } }, - "bidder" : { - "trustx" : { - "networkName" : "test-network" + "bidder": { + "trustx": { + "networkName": "test-network" } }, "origbidcpm": 10 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/undertone/test-undertone-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/undertone/test-undertone-bid-request.json index 6034271f5f3..7929f3dcd2a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/undertone/test-undertone-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/undertone/test-undertone-bid-request.json @@ -33,7 +33,7 @@ "tid": "${json-unit.any-string}" }, "regs": { - "gdpr": 0 + "gdpr": 0 }, "ext": { "id": 3, diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vidazoo/test-vidazoo-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/vidazoo/test-vidazoo-bid-request.json index dd094df0cd6..4a405f2e47a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/vidazoo/test-vidazoo-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/vidazoo/test-vidazoo-bid-request.json @@ -39,7 +39,7 @@ "USD" ], "regs": { - "gdpr": 0 + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/videobyte/test-videobyte-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/videobyte/test-videobyte-bid-request.json index b5435ae3ffc..3c3a785da23 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/videobyte/test-videobyte-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/videobyte/test-videobyte-bid-request.json @@ -19,7 +19,7 @@ } } ], - "source":{ + "source": { "tid": "${json-unit.any-string}" }, "site": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/visiblemeasures/test-visiblemeasures-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/visiblemeasures/test-visiblemeasures-bid-request.json index ec52eb6121a..e94c3e038b7 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/visiblemeasures/test-visiblemeasures-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/visiblemeasures/test-visiblemeasures-bid-request.json @@ -10,8 +10,8 @@ }, "ext": { "bidder": { - "type" : "publisher", - "placementId" : "id" + "type": "publisher", + "placementId": "id" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vox/test-vox-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/vox/test-vox-bid-response.json index 3f694f66da3..36636f50ce4 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/vox/test-vox-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/vox/test-vox-bid-response.json @@ -2,16 +2,18 @@ "id": "tid", "seatbid": [ { - "bid": [{ - "crid": "24080", - "adid": "2068416", - "cid": "8048", - "id": "bid_id", - "impid": "imp_id", - "price": 3.1415, - "adm": "

Hi, there

", - "mtype": 1 - }], + "bid": [ + { + "crid": "24080", + "adid": "2068416", + "cid": "8048", + "id": "bid_id", + "impid": "imp_id", + "price": 3.1415, + "adm": "

Hi, there

", + "mtype": 1 + } + ], "type": "banner" } ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vungle/test-vungle-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/vungle/test-vungle-bid-request.json index baf7dab5ad2..9348868846c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/vungle/test-vungle-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/vungle/test-vungle-bid-request.json @@ -3,7 +3,7 @@ "imp": [ { "id": "imp_id", - "tagid" : "placement_reference_id", + "tagid": "placement_reference_id", "secure": 1, "video": { "mimes": [ @@ -13,14 +13,14 @@ "h": 600 }, "ext": { - "bidder" : { - "bid_token" : "bid_token", - "app_store_id" : "app_store_id", - "placement_reference_id" : "placement_reference_id" + "bidder": { + "bid_token": "bid_token", + "app_store_id": "app_store_id", + "placement_reference_id": "placement_reference_id" }, - "vungle" : { - "app_store_id" : "app_store_id", - "placement_reference_id" : "placement_reference_id" + "vungle": { + "app_store_id": "app_store_id", + "placement_reference_id": "placement_reference_id" } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yahooads/test-auction-yahooads-request.json b/src/test/resources/org/prebid/server/it/openrtb2/yahooads/test-auction-yahooads-request.json index fc5d0ee2c1a..46bf0567682 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/yahooads/test-auction-yahooads-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/yahooads/test-auction-yahooads-request.json @@ -17,10 +17,12 @@ ], "tmax": 5000, "regs": { - "gpp": "gppstring", - "gpp_sid": [6], "ext": { - "gdpr": 0 + "gdpr": 0, + "gpp": "gppstring", + "gpp_sid": [ + 6 + ] } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yahooads/test-yahooads-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/yahooads/test-yahooads-bid-request.json index 54cece45a31..42187c61655 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/yahooads/test-yahooads-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/yahooads/test-yahooads-bid-request.json @@ -42,11 +42,11 @@ "ip": "193.168.244.1" }, "regs": { - "ext": { - "gpp": "gppstring", - "gpp_sid": [6], - "gdpr": 0 - } + "gpp": "gppstring", + "gpp_sid": [ + 6 + ], + "gdpr": 0 }, "ext": { "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yandex/test-yandex-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/yandex/test-yandex-bid-request.json index ef8aadaf652..2ded7bc2420 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/yandex/test-yandex-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/yandex/test-yandex-bid-request.json @@ -8,8 +8,8 @@ "w": 300, "h": 600 }, - "displaymanager" : "prebid.java", - "displaymanagerver" : "1.1", + "displaymanager": "prebid.java", + "displaymanagerver": "1.1", "ext": { "tid": "${json-unit.any-string}", "bidder": { @@ -38,7 +38,7 @@ }, "at": 1, "tmax": "${json-unit.any-number}", - "cur" : [ + "cur": [ "USD" ], "regs": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yearxero/test-auction-yearxero-request.json b/src/test/resources/org/prebid/server/it/openrtb2/yearxero/test-auction-yearxero-request.json index 7b27a7bd838..dfa8278a7c1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/yearxero/test-auction-yearxero-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/yearxero/test-auction-yearxero-request.json @@ -13,7 +13,10 @@ }, "ext": { "yearxero": { - "customParams": {"custom1": "param1", "custom2": "param2"} + "customParams": { + "custom1": "param1", + "custom2": "param2" + } } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yearxero/test-yearxero-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/yearxero/test-yearxero-bid-request.json index b0cc3917b24..be4643113db 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/yearxero/test-yearxero-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/yearxero/test-yearxero-bid-request.json @@ -14,7 +14,12 @@ "secure": 1, "ext": { "tid": "${json-unit.any-string}", - "bidder": {"customParams": {"custom1": "param1", "custom2": "param2"}} + "bidder": { + "customParams": { + "custom1": "param1", + "custom2": "param2" + } + } } } ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-yieldmo-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-yieldmo-bid-response.json index 9679171d65e..e02ddb58714 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-yieldmo-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-yieldmo-bid-response.json @@ -13,8 +13,8 @@ "adm": "adm001", "h": 250, "w": 300, - "ext" : { - "mediatype" : "banner" + "ext": { + "mediatype": "banner" } } ] diff --git a/src/test/resources/org/prebid/server/it/openrtb2/zentotem/test-zentotem-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/zentotem/test-zentotem-bid-request.json index 5859ddb632c..d9e8948f887 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/zentotem/test-zentotem-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/zentotem/test-zentotem-bid-request.json @@ -9,7 +9,7 @@ "h": 250 }, "ext": { - "tid" : "${json-unit.any-string}", + "tid": "${json-unit.any-string}", "bidder": { "property": "value" } @@ -38,9 +38,9 @@ "cur": [ "USD" ], - "regs" : { - "ext" : { - "gdpr" : 0 + "regs": { + "ext": { + "gdpr": 0 } }, "ext": { diff --git a/src/test/resources/org/prebid/server/it/test-application.properties b/src/test/resources/org/prebid/server/it/test-application.properties index 422675ce9f9..41a8ecc8636 100644 --- a/src/test/resources/org/prebid/server/it/test-application.properties +++ b/src/test/resources/org/prebid/server/it/test-application.properties @@ -82,6 +82,8 @@ adapters.adprime.enabled=true adapters.adprime.endpoint=http://localhost:8090/adprime-exchange adapters.adquery.enabled=true adapters.adquery.endpoint=http://localhost:8090/adquery-exchange +adapters.adswag.enabled=true +adapters.adswag.endpoint=http://localhost:8090/adswag-exchange adapters.adtarget.enabled=true adapters.adtarget.endpoint=http://localhost:8090/adtarget-exchange adapters.adtelligent.enabled=true @@ -170,6 +172,8 @@ adapters.bidstack.enabled=true adapters.bidstack.endpoint=http://localhost:8090/bidstack-exchange adapters.bidtheatre.enabled=true adapters.bidtheatre.endpoint=http://localhost:8090/bidtheatre-exchange +adapters.bidwave.enabled=true +adapters.bidwave.endpoint=http://localhost:8090/bidwave-exchange adapters.bigoad.enabled=true adapters.bigoad.endpoint=http://localhost:8090/bigoad-exchange adapters.blasto.enabled=true @@ -250,6 +254,8 @@ adapters.epsilon.endpoint=http://localhost:8090/epsilon-exchange adapters.epsilon.generate-bid-id=false adapters.escalax.enabled=true adapters.escalax.endpoint=http://localhost:8090/escalax-exchange +adapters.eskimi.enabled=true +adapters.eskimi.endpoint=http://localhost:8090/eskimi-exchange adapters.evolution.enabled=true adapters.evolution.endpoint=http://localhost:8090/evolution-exchange adapters.exco.enabled=true @@ -261,6 +267,8 @@ adapters.flatads.enabled=true adapters.flatads.endpoint=http://localhost:8090/flatads-exchange adapters.flipp.enabled=true adapters.flipp.endpoint=http://localhost:8090/flipp-exchange +adapters.floxis.enabled=true +adapters.floxis.endpoint=http://localhost:8090/floxis-exchange adapters.audiencenetwork.enabled=true adapters.audiencenetwork.endpoint=http://localhost:8090/audienceNetwork-exchange adapters.audiencenetwork.timeout-notification-url-template=http://localhost:8090/audienceNetwork-timeout @@ -505,6 +513,8 @@ adapters.magnite.usersync.redirect.url=http://localhost:8090/magnite-usersync?gd adapters.magnite.usersync.redirect.uid-macro=magnite-macro adapters.salunamedia.enabled=true adapters.salunamedia.endpoint=http://localhost:8090/salunamedia-exchange +adapters.scalibur.enabled=true +adapters.scalibur.endpoint=http://localhost:8090/scalibur-exchange adapters.screencore.enabled=true adapters.screencore.endpoint=http://localhost:8090/screencore-exchange adapters.seedingAlliance.enabled=true @@ -515,6 +525,8 @@ adapters.seedingAlliance.aliases.finative.enabled=true adapters.seedingAlliance.aliases.finative.endpoint=http://localhost:8090/finative-exchange adapters.seedtag.enabled=true adapters.seedtag.endpoint=http://localhost:8090/seedtag-exchange +adapters.sevio.enabled=true +adapters.sevio.endpoint=http://localhost:8090/sevio-exchange adapters.smaato.enabled=true adapters.smaato.endpoint=http://localhost:8090/smaato-exchange adapters.smartadserver.enabled=true @@ -577,6 +589,8 @@ adapters.startio.enabled=true adapters.startio.endpoint=http://localhost:8090/startio-exchange adapters.stroeercore..enabled=true adapters.stroeercore.endpoint=http://localhost:8090/stroeercore-exchange +adapters.synapsehx.enabled=true +adapters.synapsehx.endpoint=http://localhost:8090/synapsehx-exchange adapters.suntContent.enabled=true adapters.suntContent.endpoint=http://localhost:8090/suntContent-exchange adapters.taboola.enabled=true @@ -609,6 +623,8 @@ adapters.teqblaze.aliases.mycodemedia.enabled=true adapters.teqblaze.aliases.mycodemedia.endpoint=http://localhost:8090/mycodemedia-exchange/ adapters.teqblaze.aliases.adsmovil.enabled=true adapters.teqblaze.aliases.adsmovil.endpoint=http://localhost:8090/adsmovil-exchange/ +adapters.teqblaze.aliases.appMonstaMedia.enabled=true +adapters.teqblaze.aliases.appMonstaMedia.endpoint=http://localhost:8090/appMonstaMedia-exchange/ adapters.theadx.enabled=true adapters.theadx.endpoint=http://localhost:8090/theadx-exchange adapters.tradplus.enabled=true