-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Openx bid adapter: WIP deduplicate request #14477
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -162,37 +162,11 @@ function isBidRequestValid(bidRequest) { | |
| } | ||
|
|
||
| function buildRequests(bidRequests, bidderRequest) { | ||
| const videoRequests = bidRequests.filter(bidRequest => isVideoBidRequest(bidRequest)); | ||
| const bannerAndNativeRequests = bidRequests.filter(bidRequest => isBannerBidRequest(bidRequest) || isNativeBidRequest(bidRequest)) | ||
| // In case of multi-format bids remove `video` from mediaTypes as for video a separate bid request is built | ||
| .map(bid => ({...bid, mediaTypes: {...bid.mediaTypes, video: undefined}})); | ||
|
|
||
| const requests = bannerAndNativeRequests.length ? [createRequest(bannerAndNativeRequests, bidderRequest, null)] : []; | ||
| videoRequests.forEach(bid => { | ||
| requests.push(createRequest([bid], bidderRequest, VIDEO)); | ||
| }); | ||
| return requests; | ||
| } | ||
|
|
||
| function createRequest(bidRequests, bidderRequest, mediaType) { | ||
| return { | ||
| return [{ | ||
| method: 'POST', | ||
| url: config.getConfig('openxOrtbUrl') || REQUEST_URL, | ||
| data: converter.toORTB({bidRequests, bidderRequest, context: {mediaType}}) | ||
| } | ||
| } | ||
|
|
||
| function isVideoBidRequest(bidRequest) { | ||
| return utils.deepAccess(bidRequest, 'mediaTypes.video'); | ||
| } | ||
|
|
||
| function isNativeBidRequest(bidRequest) { | ||
| return utils.deepAccess(bidRequest, 'mediaTypes.native'); | ||
| } | ||
|
|
||
| function isBannerBidRequest(bidRequest) { | ||
| const isNotVideoOrNativeBid = !isVideoBidRequest(bidRequest) && !isNativeBidRequest(bidRequest) | ||
| return utils.deepAccess(bidRequest, 'mediaTypes.banner') || isNotVideoOrNativeBid; | ||
| data: converter.toORTB({bidRequests, bidderRequest}) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Removing the Useful? React with 👍 / 👎. |
||
| }]; | ||
| } | ||
|
|
||
| function interpretResponse(resp, req) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -416,16 +416,12 @@ describe('OpenxRtbAdapter', function () { | |
| playerSize: [640, 480] | ||
| }; | ||
| const requests = spec.buildRequests([multiformat], mockBidderRequest); | ||
| expect(requests).to.have.length(2); | ||
| expect(requests).to.have.length(1); | ||
| expect(requests[0].data.imp).to.have.length(1); | ||
| expect(requests[0].data.imp[0].banner).to.exist; | ||
| expect(requests[0].data.imp[0].video).to.not.exist; | ||
| expect(requests[0].data.imp[0].native).to.not.exist; | ||
| expect(requests[1].data.imp).to.have.length(1); | ||
| expect(requests[1].data.imp[0].banner).to.not.exist; | ||
| expect(requests[1].data.imp[0].native).to.not.exist; | ||
| if (FEATURES.VIDEO) { | ||
| expect(requests[1].data.imp[0].video).to.exist; | ||
| expect(requests[0].data.imp[0].video).to.exist; | ||
| } | ||
| }) | ||
|
|
||
|
|
@@ -454,21 +450,33 @@ describe('OpenxRtbAdapter', function () { | |
| sizes: [[300, 250]] | ||
| } | ||
| const requests = spec.buildRequests([multiformat], mockBidderRequest); | ||
| expect(requests).to.have.length(2); | ||
| expect(requests).to.have.length(1); | ||
| expect(requests[0].data.imp).to.have.length(1); | ||
| expect(requests[0].data.imp[0].banner).to.exist; | ||
| expect(requests[0].data.imp[0].video).to.not.exist; | ||
| if (FEATURES.NATIVE) { | ||
| expect(requests[0].data.imp[0].native).to.exist; | ||
| } | ||
| expect(requests[1].data.imp).to.have.length(1); | ||
| expect(requests[1].data.imp[0].banner).to.not.exist; | ||
| expect(requests[1].data.imp[0].native).to.not.exist; | ||
| if (FEATURES.VIDEO) { | ||
| expect(requests[1].data.imp[0].video).to.exist; | ||
| expect(requests[0].data.imp[0].video).to.exist; | ||
| } | ||
| }) | ||
|
|
||
| it('should send banner, video and native bids in a single HTTP request', function () { | ||
| const allBids = [...bidRequestsWithMediaTypes, nativeBidRequest]; | ||
| const request = spec.buildRequests(allBids, mockBidderRequest); | ||
| expect(request).to.have.length(1); | ||
| expect(request[0].data.imp).to.have.length(3); | ||
| expect(request[0].data.imp[0].banner).to.exist; | ||
| if (FEATURES.VIDEO) { | ||
| const videoImp = request[0].data.imp.find(imp => imp.id === bidRequestsWithMediaTypes[1].bidId); | ||
| expect(videoImp.video).to.exist; | ||
| } | ||
| if (FEATURES.NATIVE) { | ||
| const nativeImp = request[0].data.imp.find(imp => imp.id === nativeBidRequest.bidId); | ||
| expect(nativeImp.native).to.exist; | ||
| } | ||
| }); | ||
|
|
||
| it('should send bid request to openx url via POST', function () { | ||
| const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); | ||
| expect(request[0].url).to.equal(REQUEST_URL); | ||
|
|
@@ -482,19 +490,26 @@ describe('OpenxRtbAdapter', function () { | |
| expect(request[0].data.ext.platformId).to.be.undefined; | ||
| }); | ||
|
|
||
| it('should send platform id, if available', function () { | ||
| it('should send platform id from first bid, if available', function () { | ||
| bidRequestsWithMediaTypes[0].params.platform = '1cabba9e-cafe-3665-beef-f00f00f00f00'; | ||
| bidRequestsWithMediaTypes[1].params.platform = '51ca3159-abc2-4035-8e00-fe26eaa09397'; | ||
|
|
||
| const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); | ||
| expect(request.length).to.equal(1); | ||
| expect(request[0].data.ext.platform).to.equal(bidRequestsWithMediaTypes[0].params.platform); | ||
| expect(request[1].data.ext.platform).to.equal(bidRequestsWithMediaTypes[1].params.platform); | ||
| }); | ||
|
|
||
| it('should send delDomain from first bid when bids have different delDomains', function () { | ||
| bidRequestsWithMediaTypes[0].params.delDomain = 'domain-a.test'; | ||
| bidRequestsWithMediaTypes[1].params.delDomain = 'domain-b.test'; | ||
| const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); | ||
| expect(request[0].data.ext.delDomain).to.equal('domain-a.test'); | ||
| }); | ||
|
|
||
| it('should send openx adunit codes', function () { | ||
| const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); | ||
| expect(request[0].data.imp[0].tagid).to.equal(bidRequestsWithMediaTypes[0].params.unit); | ||
| expect(request[1].data.imp[0].tagid).to.equal(bidRequestsWithMediaTypes[1].params.unit); | ||
| expect(request[0].data.imp[1].tagid).to.equal(bidRequestsWithMediaTypes[1].params.unit); | ||
| }); | ||
|
|
||
| it('should send out custom params on bids that have customParams specified', function () { | ||
|
|
@@ -563,7 +578,7 @@ describe('OpenxRtbAdapter', function () { | |
| expect(request[0].data.imp[0].bidfloorcur).to.equal('USD'); | ||
| }); | ||
|
|
||
| it('should send not send floors', function () { | ||
| it('should not send floors', function () { | ||
| adServerCurrencyStub.returns('EUR'); | ||
| const bidRequest = Object.assign({}, | ||
| bidRequestsWithMediaTypes[0], | ||
|
|
@@ -904,7 +919,6 @@ describe('OpenxRtbAdapter', function () { | |
| it('should send a signal to specify that US Privacy applies to this request', async function () { | ||
| const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)); | ||
| expect(request[0].data.regs.ext.us_privacy).to.equal('1YYN'); | ||
| expect(request[1].data.regs.ext.us_privacy).to.equal('1YYN'); | ||
| }); | ||
|
|
||
| it('should not send the regs object, when consent string is undefined', async function () { | ||
|
|
@@ -946,29 +960,25 @@ describe('OpenxRtbAdapter', function () { | |
| bidderRequest.bids = bidRequests; | ||
| const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)); | ||
| expect(request[0].data.regs.ext.gdpr).to.equal(1); | ||
| expect(request[1].data.regs.ext.gdpr).to.equal(1); | ||
| }); | ||
|
|
||
| it('should send the consent string', async function () { | ||
| bidderRequest.bids = bidRequests; | ||
| const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)); | ||
| expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); | ||
| expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); | ||
| }); | ||
|
|
||
| it('should send the addtlConsent string', async function () { | ||
| bidderRequest.bids = bidRequests; | ||
| const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)); | ||
| expect(request[0].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent); | ||
| expect(request[1].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent); | ||
| }); | ||
|
|
||
| it('should send a signal to specify that GDPR does not apply to this request', async function () { | ||
| bidderRequest.gdprConsent.gdprApplies = false; | ||
| bidderRequest.bids = bidRequests; | ||
| const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)); | ||
| expect(request[0].data.regs.ext.gdpr).to.equal(0); | ||
| expect(request[1].data.regs.ext.gdpr).to.equal(0); | ||
| }); | ||
|
|
||
| it('when GDPR application is undefined, should not send a signal to specify whether GDPR applies to this request, ' + | ||
|
|
@@ -978,15 +988,14 @@ describe('OpenxRtbAdapter', function () { | |
| const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)); | ||
| expect(request[0].data.regs?.ext?.gdpr).to.not.be.ok; | ||
| expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); | ||
| expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); | ||
| }); | ||
|
|
||
| it('when consent string is undefined, should not send the consent string, ', async function () { | ||
| delete bidderRequest.gdprConsent.consentString; | ||
| bidderRequest.bids = bidRequests; | ||
| const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)); | ||
| expect(request[0].data.imp[0].ext.consent).to.equal(undefined); | ||
| expect(request[1].data.imp[0].ext.consent).to.equal(undefined); | ||
| expect(request[0].data.imp[1].ext.consent).to.equal(undefined); | ||
| }); | ||
| }); | ||
|
|
||
|
|
@@ -1002,8 +1011,6 @@ describe('OpenxRtbAdapter', function () { | |
| const request = spec.buildRequests(bidRequests, bidderRequest); | ||
| expect(request[0].data.regs.gpp).to.equal('test-gpp-string'); | ||
| expect(request[0].data.regs.gpp_sid).to.deep.equal([6]); | ||
| expect(request[1].data.regs.gpp).to.equal('test-gpp-string'); | ||
| expect(request[1].data.regs.gpp_sid).to.deep.equal([6]); | ||
| }); | ||
|
|
||
| it('should not send GPP string and GPP section IDs in bid request when not available', async function () { | ||
|
|
@@ -1014,8 +1021,6 @@ describe('OpenxRtbAdapter', function () { | |
| const request = spec.buildRequests(bidRequests, bidderRequest); | ||
| expect(request[0].data.regs.gpp).to.not.exist; | ||
| expect(request[0].data.regs.gpp_sid).to.not.exist; | ||
| expect(request[1].data.regs.gpp).to.not.exist; | ||
| expect(request[1].data.regs.gpp_sid).to.not.exist; | ||
| }); | ||
| }); | ||
| }); | ||
|
|
@@ -1251,7 +1256,7 @@ describe('OpenxRtbAdapter', function () { | |
| context('video', function () { | ||
| it('should send bid request with a mediaTypes specified with video type', function () { | ||
| const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); | ||
| expect(request[1].data.imp[0]).to.have.any.keys(VIDEO); | ||
| expect(request[0].data.imp[1]).to.have.any.keys(VIDEO); | ||
| }); | ||
|
|
||
| it('Update imp.video with OpenRTB options from mimeTypes and params', function() { | ||
|
|
@@ -1288,8 +1293,8 @@ describe('OpenxRtbAdapter', function () { | |
| h: 250 | ||
| }; | ||
| const requests = spec.buildRequests([bid01], bidderRequest); | ||
| expect(requests).to.have.lengthOf(2); | ||
| expect(requests[1].data.imp[0].video).to.deep.equal(expected); | ||
| expect(requests).to.have.lengthOf(1); | ||
| expect(requests[0].data.imp[0].video).to.deep.equal(expected); | ||
| }); | ||
| }); | ||
| } | ||
|
|
@@ -1573,6 +1578,7 @@ describe('OpenxRtbAdapter', function () { | |
| crid: 'test-creative-id', | ||
| dealid: 'test-deal-id', | ||
| adm: '<VAST version="4.0"><Ad></Ad></VAST>', | ||
| mtype: 2, | ||
|
||
| }] | ||
| }], | ||
| cur: 'AUS' | ||
|
|
@@ -1693,6 +1699,39 @@ describe('OpenxRtbAdapter', function () { | |
| }); | ||
| } | ||
|
|
||
| context('when multiple bid requests (banner + video) are in one request and both bids are returned', function() { | ||
| it('should correctly return both banner and video bids', function () { | ||
| const bidRequestConfigs = [ | ||
| { | ||
| bidder: 'openx', params: { unit: '1', delDomain: 'test-del-domain' }, | ||
| adUnitCode: 'au-1', mediaTypes: { banner: { sizes: [[300, 250]] } }, | ||
| bidId: 'bid-id-banner', bidderRequestId: 'br-1', auctionId: 'a-1' | ||
| }, | ||
| { | ||
| bidder: 'openx', params: { unit: '2', delDomain: 'test-del-domain' }, | ||
| adUnitCode: 'au-2', mediaTypes: { video: { playerSize: [640, 480] } }, | ||
| bidId: 'bid-id-video', bidderRequestId: 'br-1', auctionId: 'a-1' | ||
| } | ||
| ]; | ||
| const bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0]; | ||
| const bidResponse = { | ||
| seatbid: [{ | ||
| bid: [ | ||
| { impid: 'bid-id-banner', price: 1, adm: '<div>ad</div>', mtype: 1 }, | ||
| { impid: 'bid-id-video', price: 2, adm: '<VAST/>', mtype: 2 } | ||
| ] | ||
| }], | ||
| cur: 'USD' | ||
| }; | ||
| const result = spec.interpretResponse({ body: bidResponse }, bidRequest); | ||
| expect(result.bids).to.have.length(2); | ||
| expect(result.bids[0].mediaType).to.equal(BANNER); | ||
| expect(result.bids[1].mediaType).to.equal(VIDEO); | ||
| expect(result.bids[0].requestId).to.equal('bid-id-banner'); | ||
| expect(result.bids[1].requestId).to.equal('bid-id-video'); | ||
| }); | ||
| }); | ||
|
|
||
| if (FEATURES.NATIVE) { | ||
| context('when native request and the response is a native', function() { | ||
| beforeEach(function () { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The simplified request consolidation now uses only the first bid request's parameters for request-level fields (platform, delDomain, coppa, doNotTrack, response_template_name, test - see lines 60-78 of the converter configuration). If different bid requests specify different values for these parameters, only the first request's values will be used. Consider validating that all bid requests have consistent request-level parameters, or document this limitation so publishers understand these parameters must be consistent across all ad units in an auction.