@@ -9,6 +9,7 @@ import org.prebid.server.functional.model.db.Account
99import org.prebid.server.functional.model.request.auction.BidRequest
1010import org.prebid.server.functional.model.request.auction.Device
1111import org.prebid.server.functional.model.request.auction.DeviceExt
12+ import org.prebid.server.functional.model.request.auction.Imp
1213import org.prebid.server.functional.model.request.auction.PrebidStoredRequest
1314import org.prebid.server.functional.model.request.auction.Renderer
1415import org.prebid.server.functional.model.request.auction.RendererData
@@ -47,15 +48,17 @@ class AuctionSpec extends BaseSpec {
4748 private static final Integer DEFAULT_TIMEOUT = getRandomTimeout()
4849 private static final Integer MIN_BID_ID_LENGTH = 17
4950 private static final Integer DEFAULT_UUID_LENGTH = 36
50- private static final Map<String , String > PBS_CONFIG = [" auction.biddertmax.max" : MAX_TIMEOUT as String ,
51- " auction.default-timeout-ms" : DEFAULT_TIMEOUT as String ]
5251 private static final Map<String , String > GENERIC_CONFIG = [
5352 " adapters.${ GENERIC.value} .usersync.${ USER_SYNC_TYPE.value} .url" : USER_SYNC_URL ,
5453 " adapters.${ GENERIC.value} .usersync.${ USER_SYNC_TYPE.value} .support-cors" : CORS_SUPPORT . toString()]
55-
5654 @Shared
5755 PrebidServerService prebidServerService = pbsServiceFactory. getService(PBS_CONFIG )
5856
57+ private static final String IMPS_REQUESTED_METRIC = ' imps_requested'
58+ private static final String IMPS_DROPPED_METRIC = ' imps_dropped'
59+ private static final Map<String , String > PBS_CONFIG = [" auction.biddertmax.max" : MAX_TIMEOUT as String ,
60+ " auction.default-timeout-ms" : DEFAULT_TIMEOUT as String ]
61+
5962 def " PBS should return version in response header for auction request for #description" () {
6063 when : " PBS processes auction request"
6164 def response = defaultPbsService. sendAuctionRequestRaw(bidRequest)
@@ -721,4 +724,152 @@ class AuctionSpec extends BaseSpec {
721724 cleanup : " Stop and remove pbs container"
722725 pbsServiceFactory. removeContainer(pbsConfig)
723726 }
727+
728+ def " PBS should drop extra impressions with warnings when number of impressions exceeds impression-limit" () {
729+ given : " Bid request with multiple imps"
730+ def bidRequest = BidRequest . defaultBidRequest. tap {
731+ imp. add(Imp . getDefaultImpression())
732+ }
733+
734+ and : " Account in the DB with impression limit config"
735+ def impressionLimit = 1
736+ def accountConfig = new AccountConfig (auction : accountAuctionConfig)
737+ def account = new Account (uuid : bidRequest. getAccountId(), config : accountConfig)
738+ accountDao. save(account)
739+
740+ and : " Flush metrics"
741+ flushMetrics(defaultPbsService)
742+
743+ when : " PBS processes auction request"
744+ def response = defaultPbsService. sendAuctionRequest(bidRequest)
745+
746+ then : " Response should contain seatNonBid"
747+ assert ! response?. ext?. seatnonbid
748+
749+ and : " PBS should emit an warning"
750+ assert response. ext?. warnings[PREBID ]* . code == [999 ]
751+ assert response. ext?. warnings[PREBID ]* . message ==
752+ [" Only first $impressionLimit impressions were kept due to the limit, " +
753+ " all the subsequent impressions have been dropped for the auction" as String ]
754+
755+ and : " PBS shouldn't emit an error"
756+ assert ! response. ext?. errors
757+
758+ and : " Metrics for imps should be updated"
759+ def metrics = defaultPbsService. sendCollectedMetricsRequest()
760+ assert metrics[IMPS_DROPPED_METRIC ] == bidRequest. imp. size() - impressionLimit
761+ assert metrics[IMPS_REQUESTED_METRIC ] == impressionLimit
762+
763+ and : " Response should contain seat bid"
764+ assert response. seatbid[0 ]. bid. size() == impressionLimit
765+
766+ where :
767+ accountAuctionConfig << [
768+ new AccountAuctionConfig (impressionLimit : impressionLimit),
769+ new AccountAuctionConfig (impressionLimitSnakeCase : impressionLimit)
770+ ]
771+ }
772+
773+ def " PBS shouldn't drop extra impressions when number of impressions equal to impression-limit" () {
774+ given : " Bid request with multiple imps"
775+ def bidRequest = BidRequest . defaultBidRequest. tap {
776+ imp. add(Imp . getDefaultImpression())
777+ }
778+
779+ and : " Account in the DB with impression limit config"
780+ def accountConfig = new AccountConfig (auction : new AccountAuctionConfig (impressionLimit : bidRequest. imp. size()))
781+ def account = new Account (uuid : bidRequest. getAccountId(), config : accountConfig)
782+ accountDao. save(account)
783+
784+ and : " Flush metrics"
785+ flushMetrics(defaultPbsService)
786+
787+ when : " PBS processes auction request"
788+ def response = defaultPbsService. sendAuctionRequest(bidRequest)
789+
790+ then : " Response should contain seatNonBid"
791+ assert ! response?. ext?. seatnonbid
792+
793+ and : " Response shouldn't contain warnings and error"
794+ assert ! response. ext?. warnings
795+ assert ! response. ext?. errors
796+
797+ and : " Metrics for imps requested should be updated"
798+ def metrics = defaultPbsService. sendCollectedMetricsRequest()
799+ assert metrics[IMPS_DROPPED_METRIC ] == 0
800+ assert metrics[IMPS_REQUESTED_METRIC ] == bidRequest. imp. size()
801+
802+ and : " Response should contain seat bid"
803+ assert response. seatbid[0 ]. bid. size() == bidRequest. imp. size()
804+ }
805+
806+ def " PBS shouldn't drop extra impressions when number of impressions less than or equal to impression-limit" () {
807+ given : " Bid request with multiple imps"
808+ def bidRequest = BidRequest . defaultBidRequest. tap {
809+ imp. add(Imp . getDefaultImpression())
810+ }
811+
812+ and : " Account in the DB with impression limit config"
813+ def impressionLimit = bidRequest. imp. size() + 1
814+ def accountConfig = new AccountConfig (auction : new AccountAuctionConfig (impressionLimit : impressionLimit))
815+ def account = new Account (uuid : bidRequest. getAccountId(), config : accountConfig)
816+ accountDao. save(account)
817+
818+ and : " Flush metrics"
819+ flushMetrics(defaultPbsService)
820+
821+ when : " PBS processes auction request"
822+ def response = defaultPbsService. sendAuctionRequest(bidRequest)
823+
824+ then : " Response should contain seatNonBid"
825+ assert ! response?. ext?. seatnonbid
826+
827+ and : " Response shouldn't contain warnings and error"
828+ assert ! response. ext?. warnings
829+ assert ! response. ext?. errors
830+
831+ and : " Metrics for imps requested should be updated"
832+ def metrics = defaultPbsService. sendCollectedMetricsRequest()
833+ assert metrics[IMPS_DROPPED_METRIC ] == 0
834+ assert metrics[IMPS_REQUESTED_METRIC ] == bidRequest. imp. size()
835+
836+ and : " Response should contain seat bid"
837+ assert response. seatbid[0 ]. bid. size() == bidRequest. imp. size()
838+ }
839+
840+ def " PBS shouldn't drop extra impressions when impression-limit set to #impressionLimit" () {
841+ given : " Bid request with multiple imps"
842+ def bidRequest = BidRequest . defaultBidRequest. tap {
843+ imp. add(Imp . getDefaultImpression())
844+ }
845+
846+ and : " Account in the DB with impression limit config"
847+ def accountConfig = new AccountConfig (auction : new AccountAuctionConfig (impressionLimit : impressionLimit))
848+ def account = new Account (uuid : bidRequest. getAccountId(), config : accountConfig)
849+ accountDao. save(account)
850+
851+ and : " Flush metrics"
852+ flushMetrics(defaultPbsService)
853+
854+ when : " PBS processes auction request"
855+ def response = defaultPbsService. sendAuctionRequest(bidRequest)
856+
857+ then : " Response should contain seatNonBid"
858+ assert ! response?. ext?. seatnonbid
859+
860+ and : " Response shouldn't contain warnings and error"
861+ assert ! response. ext?. warnings
862+ assert ! response. ext?. errors
863+
864+ and : " Metrics for imps requested should be updated"
865+ def metrics = defaultPbsService. sendCollectedMetricsRequest()
866+ assert metrics[IMPS_DROPPED_METRIC ] == 0
867+ assert metrics[IMPS_REQUESTED_METRIC ] == bidRequest. imp. size()
868+
869+ and : " Response should contain seat bid"
870+ assert response. seatbid[0 ]. bid. size() == bidRequest. imp. size()
871+
872+ where :
873+ impressionLimit << [null , 0 ]
874+ }
724875}
0 commit comments