Skip to content
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
13 changes: 5 additions & 8 deletions src/main/java/org/prebid/server/auction/BidResponseCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -1719,7 +1719,11 @@ private static boolean eventsEnabledForAccount(AuctionContext auctionContext) {
}

private static boolean eventsEnabledForRequest(AuctionContext auctionContext) {
return eventsEnabledForChannel(auctionContext) || eventsAllowedByRequest(auctionContext);
return Optional.ofNullable(auctionContext.getBidRequest().getExt())
.map(ExtRequest::getPrebid)
.map(ExtRequestPrebid::getEvents)
.map(eventsNode -> eventsNode.at("/enabled").asBoolean(true))
.orElseGet(() -> eventsEnabledForChannel(auctionContext));
}

private static boolean eventsEnabledForChannel(AuctionContext auctionContext) {
Expand Down Expand Up @@ -1754,13 +1758,6 @@ private static String recogniseChannelName(String channelName) {
return channelName;
}

private static boolean eventsAllowedByRequest(AuctionContext auctionContext) {
final ExtRequest ext = auctionContext.getBidRequest().getExt();
final ExtRequestPrebid prebid = ext != null ? ext.getPrebid() : null;

return prebid != null && prebid.getEvents() != null;
}

private long auctionTimestamp(AuctionContext auctionContext) {
final ExtRequest ext = auctionContext.getBidRequest().getExt();
final ExtRequestPrebid prebid = ext != null ? ext.getPrebid() : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.databind.annotation.JsonNaming
import groovy.transform.ToString
import org.prebid.server.functional.model.ChannelType

@ToString(includeNames = true, ignoreNulls = true)
@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy)
class AccountAnalyticsConfig {

Map<String, Boolean> auctionEvents
Map<ChannelType, Boolean> auctionEvents
Boolean allowClientDetails
AnalyticsModule modules

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize
@JsonSerialize
class Events {

Boolean enabled
}
131 changes: 127 additions & 4 deletions src/test/groovy/org/prebid/server/functional/tests/EventsSpec.groovy
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package org.prebid.server.functional.tests

import org.prebid.server.functional.model.ChannelType
import org.prebid.server.functional.model.config.AccountAnalyticsConfig
import org.prebid.server.functional.model.config.AccountConfig
import org.prebid.server.functional.model.db.Account
import org.prebid.server.functional.model.db.StoredRequest
import org.prebid.server.functional.model.request.auction.BidRequest
import org.prebid.server.functional.model.request.auction.Events
import org.prebid.server.functional.model.request.auction.PrebidStoredRequest
import org.prebid.server.functional.util.PBSUtils

import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP
import static org.prebid.server.functional.model.request.auction.DistributionChannel.DOOH
import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE

class EventsSpec extends BaseSpec {
Expand All @@ -31,7 +36,7 @@ class EventsSpec extends BaseSpec {
assert bidResponse.seatbid[0].bid[0].ext.prebid.events.imp

where:
distributionChannel << [SITE, APP]
distributionChannel << [SITE, APP, DOOH]
}

def "PBS should not generate event tracker URLs when events are disabled for account"() {
Expand All @@ -54,7 +59,7 @@ class EventsSpec extends BaseSpec {
assert !bidResponse.seatbid[0].bid[0].ext.prebid.events?.imp

where:
distributionChannel << [SITE, APP]
distributionChannel << [SITE, APP, DOOH]
}

def "PBS should resolve publisher id for events when events are enabled for account"() {
Expand All @@ -78,7 +83,7 @@ class EventsSpec extends BaseSpec {
assert bidResponseEvents.imp.contains("a=${accountId}")

where:
distributionChannel << [SITE, APP]
distributionChannel << [SITE, APP, DOOH]
}

def "PBS should resolve publisher id from stored request for events when events enabled"() {
Expand Down Expand Up @@ -110,6 +115,124 @@ class EventsSpec extends BaseSpec {
assert bidResponseEvents.imp.contains("a=${accountId}")

where:
distributionChannel << [SITE, APP]
distributionChannel << [SITE, APP, DOOH]
}

def "Account-level analytics settings should apply when request events config is absent"() {
given: "BidRequest without events config"
def accountId = PBSUtils.randomNumber as String
def bidRequest = BidRequest.getDefaultBidRequest(requestType).tap {
setAccountId(accountId)
}

and: "Account with analytics events disabled for corresponding channel"
def analyticsConfig = new AccountAnalyticsConfig(auctionEvents: [(accountConfigChannelType): false])
def account = new Account(uuid: accountId, eventsEnabled: true, config: new AccountConfig(analytics: analyticsConfig))
accountDao.save(account)

when: "Auction request is processed"
def bidResponse = defaultPbsService.sendAuctionRequest(bidRequest)

then: "Events should not be present in response due to stored request disablement"
assert !bidResponse.seatbid[0].bid[0].ext?.prebid?.events

where:
requestType | accountConfigChannelType
SITE | ChannelType.WEB
APP | ChannelType.APP
DOOH | ChannelType.DOOH
}

def "Request level events config should override account-level analytics settings"() {
given: "BidRequest with events config"
def accountId = PBSUtils.randomNumber as String
def bidRequest = BidRequest.getDefaultBidRequest(requestType).tap {
setAccountId(accountId)
ext.prebid.events = new Events(enabled: requestEventEnablement)
}

and: "Account with analytics events disabled for corresponding channel"
def analyticsConfig = new AccountAnalyticsConfig(auctionEvents: [(accountConfigChannelType): false])
def account = new Account(uuid: accountId, eventsEnabled: true, config: new AccountConfig(analytics: analyticsConfig))
accountDao.save(account)

when: "Auction request is processed"
def bidResponse = defaultPbsService.sendAuctionRequest(bidRequest)

then: "Events should be present in response despite account-level disablement"
def bidResponseEvents = bidResponse.seatbid[0].bid[0].ext.prebid.events
assert bidResponseEvents.win.contains("a=${accountId}")
assert bidResponseEvents.imp.contains("a=${accountId}")

where:
requestEventEnablement | requestType | accountConfigChannelType
null | SITE | ChannelType.WEB
null | APP | ChannelType.APP
null | DOOH | ChannelType.DOOH

true | SITE | ChannelType.WEB
true | APP | ChannelType.APP
true | DOOH | ChannelType.DOOH
}

def "Request-level events disabled should override account-level analytics settings"() {
given: "BidRequest with events explicitly disabled at request level"
def accountId = PBSUtils.randomNumber as String

def bidRequest = BidRequest.getDefaultBidRequest(requestType).tap {
setAccountId(accountId)
ext.prebid.events = new Events(enabled: false)
}

and: "Account with analytics events enabled for corresponding channel"
def analyticsConfig = new AccountAnalyticsConfig(auctionEvents: [(accountConfigChannelType): true])
def account = new Account(uuid: accountId, eventsEnabled: true, config: new AccountConfig(analytics: analyticsConfig))
accountDao.save(account)

when: "Auction request is processed"
def bidResponse = defaultPbsService.sendAuctionRequest(bidRequest)

then: "Events should not be present in response due to request-level disablement"
assert !bidResponse.seatbid[0].bid[0].ext?.prebid?.events

where:
requestType | accountConfigChannelType
SITE | ChannelType.WEB
APP | ChannelType.APP
DOOH | ChannelType.DOOH
}

def "Stored request events config should override account-level analytics settings when request config is absent"() {
given: "BidRequest referencing stored request without events config"
def storedRequestId = PBSUtils.randomString
def bidRequest = BidRequest.getDefaultBidRequest(distributionChannel).tap {
ext.prebid.storedRequest = new PrebidStoredRequest(id: storedRequestId)
setAccountId(null)
}

and: "Stored request with account id and events disabled"
def accountId = PBSUtils.randomNumber as String
def storedRequest = BidRequest.getDefaultBidRequest(distributionChannel).tap {
setAccountId(accountId)
ext.prebid.events = new Events(enabled: false)
}
storedRequestDao.save(StoredRequest.getStoredRequest(accountId, storedRequestId, storedRequest))

and: "Account with analytics events enabled for corresponding channel"
def analyticsConfig = new AccountAnalyticsConfig(auctionEvents: [(accountConfigChannelType): true])
def account = new Account(uuid: accountId, eventsEnabled: true, config: new AccountConfig(analytics: analyticsConfig))
accountDao.save(account)

when: "Auction request is processed"
def bidResponse = defaultPbsService.sendAuctionRequest(bidRequest)

then: "Events should not be present in response due to stored request disablement"
assert !bidResponse.seatbid[0].bid[0].ext?.prebid?.events

where:
distributionChannel | accountConfigChannelType
SITE | ChannelType.WEB
APP | ChannelType.APP
DOOH | ChannelType.DOOH
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@
import org.prebid.server.auction.model.BidderResponse;
import org.prebid.server.auction.model.CachedDebugLog;
import org.prebid.server.auction.model.CategoryMappingResult;
import org.prebid.server.auction.model.ImpRejection;
import org.prebid.server.auction.model.MultiBidConfig;
import org.prebid.server.auction.model.PaaFormat;
import org.prebid.server.auction.model.ImpRejection;
import org.prebid.server.auction.model.TargetingInfo;
import org.prebid.server.auction.model.TimeoutContext;
import org.prebid.server.auction.model.debug.DebugContext;
Expand Down Expand Up @@ -163,6 +163,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.prebid.server.auction.model.BidRejectionReason.NO_BID;
import static org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidAdservertargetingRule.Source.xStatic;
import static org.prebid.server.proto.openrtb.ext.response.BidType.audio;
Expand Down Expand Up @@ -2719,6 +2720,8 @@ public void shouldNotAddExtPrebidEventsIfEventsAreNotEnabled() {
.flatExtracting(SeatBid::getBid)
.extracting(responseBid -> toExtBidPrebid(responseBid.getExt()).getEvents())
.containsNull();

verifyNoInteractions(eventsService);
}

@Test
Expand Down Expand Up @@ -2753,6 +2756,47 @@ public void shouldNotAddExtPrebidEventsIfExtRequestPrebidEventsNull() {
.flatExtracting(SeatBid::getBid)
.extracting(responseBid -> toExtBidPrebid(responseBid.getExt()).getEvents())
.containsNull();

verifyNoInteractions(eventsService);
}

@Test
public void shouldNotAddExtPrebidEventsIfExtRequestPrebidEventsEnabledIsFalse() {
// given
final Account account = Account.builder()
.id("accountId")
.auction(AccountAuctionConfig.builder()
.events(AccountEventsConfig.of(true))
.build())
.build();

final Bid bid = Bid.builder()
.id("bidId1")
.price(BigDecimal.valueOf(5.67))
.impid(IMP_ID)
.build();
final List<BidderResponse> bidderResponses = singletonList(
BidderResponse.of("bidder1", givenSeatBid(BidderBid.of(bid, banner, "seat", "USD")), 100));

final AuctionContext auctionContext = givenAuctionContext(
givenBidRequest(
identity(),
extBuilder -> extBuilder.events(mapper.createObjectNode().put("enabled", false)),
givenImp()),
contextBuilder -> contextBuilder
.account(account)
.auctionParticipations(toAuctionParticipant(bidderResponses)));

// when
final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result();

// then
assertThat(bidResponse.getSeatbid()).hasSize(1)
.flatExtracting(SeatBid::getBid)
.extracting(responseBid -> toExtBidPrebid(responseBid.getExt()).getEvents())
.containsNull();

verifyNoInteractions(eventsService);
}

@Test
Expand Down Expand Up @@ -2794,6 +2838,8 @@ public void shouldNotAddExtPrebidEventsIfAccountDoesNotSupportEventsForChannel()
.flatExtracting(SeatBid::getBid)
.extracting(responseBid -> toExtBidPrebid(responseBid.getExt()).getEvents())
.containsNull();

verifyNoInteractions(eventsService);
}

@Test
Expand Down
Loading