Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Update PBC integration #3499

Merged
merged 5 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading