Skip to content

Commit

Permalink
Core: Update PBC integration (prebid#3499)
Browse files Browse the repository at this point in the history
  • Loading branch information
And1sS authored and sergseven committed Dec 23, 2024
1 parent 8caddb8 commit fe6710a
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 7 deletions.
24 changes: 18 additions & 6 deletions src/main/java/org/prebid/server/cache/CoreCacheService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.databind.node.TextNode;
import com.iab.openrtb.response.Bid;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.prebid.server.auction.model.AuctionContext;
Expand Down Expand Up @@ -61,8 +62,6 @@ public class CoreCacheService {

private static final Logger logger = LoggerFactory.getLogger(CoreCacheService.class);

private static final Map<String, List<String>> DEBUG_HEADERS =
HttpUtil.toDebugHeaders(CacheServiceUtil.CACHE_HEADERS);
private static final String BID_WURL_ATTRIBUTE = "wurl";

private final HttpClient httpClient;
Expand All @@ -76,11 +75,16 @@ public class CoreCacheService {
private final UUIDIdGenerator idGenerator;
private final JacksonMapper mapper;

private final MultiMap cacheHeaders;
private final Map<String, List<String>> debugHeaders;

public CoreCacheService(
HttpClient httpClient,
URL endpointUrl,
String cachedAssetUrlTemplate,
long expectedCacheTimeMs,
String apiKey,
boolean isApiKeySecured,
VastModifier vastModifier,
EventsService eventsService,
Metrics metrics,
Expand All @@ -98,6 +102,11 @@ public CoreCacheService(
this.clock = Objects.requireNonNull(clock);
this.idGenerator = Objects.requireNonNull(idGenerator);
this.mapper = Objects.requireNonNull(mapper);

cacheHeaders = isApiKeySecured
? HttpUtil.headers().add(HttpUtil.X_PBC_API_KEY_HEADER, Objects.requireNonNull(apiKey))
: HttpUtil.headers();
debugHeaders = HttpUtil.toDebugHeaders(cacheHeaders);
}

public String getEndpointHost() {
Expand All @@ -121,7 +130,10 @@ public String cacheVideoDebugLog(CachedDebugLog cachedDebugLog, Integer videoCac
final List<CachedCreative> cachedCreatives = Collections.singletonList(
makeDebugCacheCreative(cachedDebugLog, cacheKey, videoCacheTtl));
final BidCacheRequest bidCacheRequest = toBidCacheRequest(cachedCreatives);
httpClient.post(endpointUrl.toString(), HttpUtil.headers(), mapper.encodeToString(bidCacheRequest),
httpClient.post(
endpointUrl.toString(),
cacheHeaders,
mapper.encodeToString(bidCacheRequest),
expectedCacheTimeMs);
return cacheKey;
}
Expand Down Expand Up @@ -155,7 +167,7 @@ private Future<BidCacheResponse> makeRequest(BidCacheRequest bidCacheRequest,
final long startTime = clock.millis();
return httpClient.post(
endpointUrl.toString(),
CacheServiceUtil.CACHE_HEADERS,
cacheHeaders,
mapper.encodeToString(bidCacheRequest),
remainingTimeout)
.map(response -> toBidCacheResponse(
Expand Down Expand Up @@ -286,7 +298,7 @@ private Future<CacheServiceResult> doCacheOpenrtb(List<CacheBid> bids,
final CacheHttpRequest httpRequest = CacheHttpRequest.of(url, body);

final long startTime = clock.millis();
return httpClient.post(url, CacheServiceUtil.CACHE_HEADERS, body, remainingTimeout)
return httpClient.post(url, cacheHeaders, body, remainingTimeout)
.map(response -> processResponseOpenrtb(response,
httpRequest,
cachedCreatives.size(),
Expand Down Expand Up @@ -348,7 +360,7 @@ private DebugHttpCall makeDebugHttpCall(String endpoint,
.responseStatus(httpResponse != null ? httpResponse.getStatusCode() : null)
.responseBody(httpResponse != null ? httpResponse.getBody() : null)
.responseTimeMillis(responseTime(startTime))
.requestHeaders(DEBUG_HEADERS)
.requestHeaders(debugHeaders)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ CoreCacheService cacheService(
@Value("${cache.path}") String path,
@Value("${cache.query}") String query,
@Value("${auction.cache.expected-request-time-ms}") long expectedCacheTimeMs,
@Value("${pbc.api.key:#{null}}") String apiKey,
@Value("${cache.api-key-secured:false}") boolean apiKeySecured,
VastModifier vastModifier,
EventsService eventsService,
HttpClient httpClient,
Expand All @@ -172,6 +174,8 @@ CoreCacheService cacheService(
CacheServiceUtil.getCacheEndpointUrl(scheme, host, path),
CacheServiceUtil.getCachedAssetUrlTemplate(scheme, host, path, query),
expectedCacheTimeMs,
apiKey,
apiKeySecured,
vastModifier,
eventsService,
metrics,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class PrebidCache extends NetworkScaffolding {
.collect { decode(it.body.toString(), BidCacheRequest) }
}

Map<String, List<String>> getRequestHeaders(String impId) {
getLastRecordedRequestHeaders(getRequest(impId))
}

@Override
HttpRequest getRequest() {
request().withMethod("POST")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import static org.prebid.server.functional.model.response.auction.MediaType.VIDE

class CacheSpec extends BaseSpec {

private final static String PBS_API_HEADER = 'x-pbc-api-key'

def "PBS should update prebid_cache.creative_size.xml metric when xml creative is received"() {
given: "Current value of metric prebid_cache.requests.ok"
def initialValue = getCurrentMetricValue(defaultPbsService, "prebid_cache.requests.ok")
Expand Down Expand Up @@ -87,6 +89,51 @@ class CacheSpec extends BaseSpec {

then: "PBS should call PBC"
assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 1

and: "PBS call shouldn't include api-key"
assert !prebidCache.getRequestHeaders(bidRequest.imp[0].id)[PBS_API_HEADER]
}

def "PBS should cache bids without api-key header when targeting is specified and api-key-secured disabled"() {
given: "Pbs config with disabled api-key-secured and pbc.api.key"
def apiKey = PBSUtils.randomString
def pbsService = pbsServiceFactory.getService(['pbc.api.key': apiKey, 'cache.api-key-secured': 'false'])

and: "Default BidRequest with cache, targeting"
def bidRequest = BidRequest.defaultBidRequest
bidRequest.enableCache()
bidRequest.ext.prebid.targeting = new Targeting()

when: "PBS processes auction request"
pbsService.sendAuctionRequest(bidRequest)

then: "PBS should call PBC"
prebidCache.getRequest()
assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 1

and: "PBS call shouldn't include api-key"
assert !prebidCache.getRequestHeaders(bidRequest.imp[0].id)[PBS_API_HEADER]
}

def "PBS should cache bids with api-key header when targeting is specified and api-key-secured enabled"() {
given: "Pbs config with api-key-secured and pbc.api.key"
def apiKey = PBSUtils.randomString
def pbsService = pbsServiceFactory.getService(['pbc.api.key': apiKey, 'cache.api-key-secured': 'true'])

and: "Default BidRequest with cache, targeting"
def bidRequest = BidRequest.defaultBidRequest
bidRequest.enableCache()
bidRequest.ext.prebid.targeting = new Targeting()

when: "PBS processes auction request"
pbsService.sendAuctionRequest(bidRequest)

then: "PBS should call PBC"
prebidCache.getRequest()
assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 1

and: "PBS call should include api-key"
assert prebidCache.getRequestHeaders(bidRequest.imp[0].id)[PBS_API_HEADER] == [apiKey]
}

def "PBS should not cache bids when targeting isn't specified"() {
Expand Down
85 changes: 84 additions & 1 deletion src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.iab.openrtb.request.Video;
import com.iab.openrtb.response.Bid;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand Down Expand Up @@ -40,6 +41,7 @@
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
import org.prebid.server.settings.model.Account;
import org.prebid.server.util.HttpUtil;
import org.prebid.server.vast.VastModifier;
import org.prebid.server.vertx.httpclient.HttpClient;
import org.prebid.server.vertx.httpclient.model.HttpClientResponse;
Expand Down Expand Up @@ -107,6 +109,8 @@ public void setUp() throws MalformedURLException, JsonProcessingException {
new URL("http://cache-service/cache"),
"http://cache-service-host/cache?uuid=",
100L,
null,
false,
vastModifier,
eventsService,
metrics,
Expand Down Expand Up @@ -371,6 +375,40 @@ public void cacheBidsOpenrtbShouldReturnExpectedDebugInfo() throws JsonProcessin
.build());
}

@Test
public void cacheBidsOpenrtbShouldUseApiKeyWhenProvided() throws MalformedURLException {
// given
target = new CoreCacheService(
httpClient,
new URL("http://cache-service/cache"),
"http://cache-service-host/cache?uuid=",
100L,
"ApiKey",
true,
vastModifier,
eventsService,
metrics,
clock,
idGenerator,
jacksonMapper);
final BidInfo bidinfo = givenBidInfo(builder -> builder.id("bidId1"));

// when
final Future<CacheServiceResult> future = target.cacheBidsOpenrtb(
singletonList(bidinfo),
givenAuctionContext(),
CacheContext.builder()
.shouldCacheBids(true)
.build(),
eventsContext);

// then
assertThat(future.result().getHttpCall().getRequestHeaders().get(HttpUtil.X_PBC_API_KEY_HEADER.toString()))
.containsExactly("ApiKey");
assertThat(captureBidCacheRequestHeaders().get(HttpUtil.X_PBC_API_KEY_HEADER.toString()))
.isEqualTo("ApiKey");
}

@Test
public void cacheBidsOpenrtbShouldReturnExpectedCacheBids() {
// given
Expand Down Expand Up @@ -694,7 +732,7 @@ public void cachePutObjectsShouldReturnResultWithEmptyListWhenPutObjectsIsEmpty(
}

@Test
public void cachePutObjectsShouldModifyVastAndCachePutObjects() throws IOException {
public void cachePutObjectsShould() throws IOException {
// given
final BidPutObject firstBidPutObject = BidPutObject.builder()
.type("json")
Expand Down Expand Up @@ -762,6 +800,45 @@ public void cachePutObjectsShouldModifyVastAndCachePutObjects() throws IOExcepti
.containsExactly(modifiedFirstBidPutObject, modifiedSecondBidPutObject, modifiedThirdBidPutObject);
}

@Test
public void cachePutObjectsShouldUseApiKeyWhenProvided() throws MalformedURLException {
// given
target = new CoreCacheService(
httpClient,
new URL("http://cache-service/cache"),
"http://cache-service-host/cache?uuid=",
100L,
"ApiKey",
true,
vastModifier,
eventsService,
metrics,
clock,
idGenerator,
jacksonMapper);

final BidPutObject firstBidPutObject = BidPutObject.builder()
.type("json")
.bidid("bidId1")
.bidder("bidder1")
.timestamp(1L)
.value(new TextNode("vast"))
.build();

// when
target.cachePutObjects(
asList(firstBidPutObject),
true,
singleton("bidder1"),
"account",
"pbjs",
timeout);

// then
assertThat(captureBidCacheRequestHeaders().get(HttpUtil.X_PBC_API_KEY_HEADER.toString()))
.isEqualTo("ApiKey");
}

private AuctionContext givenAuctionContext(UnaryOperator<Account.AccountBuilder> accountCustomizer,
UnaryOperator<BidRequest.BidRequestBuilder> bidRequestCustomizer) {

Expand Down Expand Up @@ -850,6 +927,12 @@ private BidCacheRequest captureBidCacheRequest() throws IOException {
return mapper.readValue(captor.getValue(), BidCacheRequest.class);
}

private MultiMap captureBidCacheRequestHeaders() {
final ArgumentCaptor<MultiMap> captor = ArgumentCaptor.forClass(MultiMap.class);
verify(httpClient).post(anyString(), captor.capture(), anyString(), anyLong());
return captor.getValue();
}

private Map<String, List<String>> givenDebugHeaders() {
final Map<String, List<String>> headers = new HashMap<>();
headers.put("Accept", singletonList("application/json"));
Expand Down

0 comments on commit fe6710a

Please sign in to comment.