Skip to content

Commit

Permalink
SmartRTB adapter update (#4246)
Browse files Browse the repository at this point in the history
* modules: Implement SmartRTB adapter and spec.

* Fix for-loop syntax to support IE; refactor getDomain out of exported set.

* Remove debugs, update doc

* Update test for video support

* Handle missing syncs. Add video to media types in sample ad unit

* Add null response check, update primary endpoint

* Note smrtb video requires renderer
  • Loading branch information
evanmsmrtb authored and Fawke committed Oct 14, 2019
1 parent 842e45f commit b3371df
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 52 deletions.
56 changes: 40 additions & 16 deletions modules/smartrtbBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

import * as utils from '../src/utils';
import { config } from '../src/config';
import {registerBidder} from '../src/adapters/bidderFactory';
const BIDDER_CODE = 'smartrtb';

Expand All @@ -14,6 +16,7 @@ function getDomain () {

export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [ 'banner', 'video' ],
aliases: ['smrtb'],
isBidRequestValid: function(bid) {
return (bid.params.pubId !== null &&
Expand All @@ -25,9 +28,11 @@ export const spec = {
bidderRequest.refererInfo.stack ? bidderRequest.refererInfo
: [])

let spb = (config.getConfig('userSync') && config.getConfig('userSync').syncsPerBidder)
? config.getConfig('userSync').syncsPerBidder : 5

const payload = {
start_time: utils.timestamp(),
tmax: 120,
language: window.navigator.userLanguage || window.navigator.language,
site: {
domain: getDomain(),
Expand All @@ -36,7 +41,9 @@ export const spec = {
https: (window.location.protocol === 'https:'),
referrer: bidderRequest.refererInfo.referer
},
imps: []
imps: [],
user_ids: validBidRequests[0].userId,
sync_limit: spb
};

if (bidderRequest && bidderRequest.gdprConsent) {
Expand All @@ -50,24 +57,30 @@ export const spec = {
let req = validBidRequests[x]

payload.imps.push({
pub_id: req.params.pubId,
med_id: req.params.medId,
zone_id: req.params.zoneId,
bid_id: req.bidId,
imp_id: req.transactionId,
sizes: req.sizes,
force_bid: req.params.forceBid
force_bid: req.params.forceBid,
media_types: utils.deepAccess(req, 'mediaTypes'),
has_renderer: (req.renderer !== undefined)
});
}

let params = validBidRequests[0].params
let url = params.endpoint ? params.endpoint : '//market-global.smrtb.com/json/publisher/prebid'
return {
method: 'POST',
url: '//pubs.smrtb.com/json/publisher/prebid',
url: url,
data: JSON.stringify(payload)
};
},
interpretResponse: function(serverResponse, bidRequest) {
const bidResponses = [];
if (!serverResponse || !serverResponse.body) {
return bidResponses
}

let res = serverResponse.body;
if (!res.bids || !res.bids.length) {
return []
Expand All @@ -82,8 +95,12 @@ export const spec = {
width: bid.w,
height: bid.h,
ad: bid.html,
vastUrl: bid.vast_url,
vastXml: bid.vast_xml,
mediaType: bid.html ? 'banner' : 'video',
ttl: 120,
creativeId: bid.crid,
dealId: bid.deal_id,
netRevenue: true,
currency: 'USD'
})
Expand All @@ -93,16 +110,23 @@ export const spec = {
},
getUserSyncs: function(syncOptions, serverResponses) {
const syncs = []
if (syncOptions.iframeEnabled) {
syncs.push({
type: 'iframe',
url: '//ads.smrtb.com/sync'
});
} else if (syncOptions.pixelEnabled) {
syncs.push({
type: 'image',
url: '//ads.smrtb.com/sync'
});

if (!serverResponses.length || !serverResponses[0].body) {
return syncs
}

let pixels = serverResponses[0].body.pixels
if (!pixels || !pixels.length) {
return syncs
}

for (let x = 0; x < pixels.length; x++) {
let pixel = pixels[x]

if ((pixel.type === 'iframe' && syncOptions.iframeEnabled) ||
(pixel.type === 'image' && syncOptions.pixelEnabled)) {
syncs.push(pixel)
}
}
return syncs;
}
Expand Down
19 changes: 13 additions & 6 deletions modules/smartrtbBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Maintainer: evanm@smrtb.com
# Description

Prebid adapter for Smart RTB. Requires approval and account setup.
Video is supported but requires a publisher supplied adunit renderer at this time.

# Test Parameters

Expand All @@ -17,18 +18,24 @@ Prebid adapter for Smart RTB. Requires approval and account setup.
var adUnits = [
{
code: 'test-div',
sizes: [[300, 250]],
mediaTypes: {
banner: {
sizes: [[300,250]]
},
video: { /* requires publisher supplied renderer */
context: 'outstream',
playerDimension: [640, 480]
}
},
bids: [
{
bidder: "smartrtb",
params: {
pubId: 123,
medId: "m_00a95d003340dbb2fcb8ee668a84fa",
zoneId: "z_261b6c7e7d4d4985393b293cc903d1",
force_bid: true
zoneId: "N4zTDq3PPEHBIODv7cXK",
forceBid: true
}
}
]
}
];
```
```
112 changes: 82 additions & 30 deletions test/spec/modules/smartrtbBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,66 @@ import { expect } from 'chai'
import { spec, _getPlatform } from 'modules/smartrtbBidAdapter'
import { newBidder } from 'src/adapters/bidderFactory'

const br = {
body: {
bids: [{
bid_id: '123',
cpm: 1.23,
w: 300,
h: 250,
html: '<b>deadbeef</b>',
crid: 'crid'
}],
pixels: [
{ type: 'image', url: 'http://smrtb.com/image' },
{ type: 'iframe', url: 'http://smrtb.com/iframe' }
]
}
}

const vr = {
body: {
bids: [{
bid_id: 'abc',
cpm: 2.34,
w: 640,
h: 480,
vast_url: 'https://demo.tremorvideo.com/proddev/vast/vast_inline_nonlinear.xml',
crid: 'video_crid'
}],
pixels: [
{ type: 'image', url: 'http://smrtb.com/image' },
{ type: 'iframe', url: 'http://smrtb.com/iframe' }
]
}
}

describe('SmartRTBBidAdapter', function () {
const adapter = newBidder(spec)

let bidRequest = {
let bannerRequest = {
bidId: '123',
transactionId: '456',
sizes: [[ 300, 250 ]],
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
params: {
pubId: 123,
medId: 'm_00a95d003340dbb2fcb8ee668a84fa',
zoneId: 'z_261b6c7e7d4d4985393b293cc903d1'
zoneId: 'N4zTDq3PPEHBIODv7cXK'
}
}

let videoRequest = {
bidId: 'abc',
transactionId: 'def',
mediaTypes: {
video: {
playerDimension: [640, 480]
}
},
params: {
zoneId: 'CK6gUYp58EGopLJnUvM2'
}
}

Expand All @@ -27,18 +76,16 @@ describe('SmartRTBBidAdapter', function () {

describe('isBidRequestValid', function () {
it('should return true if all params present', function () {
expect(spec.isBidRequestValid(bidRequest)).to.be.true
expect(spec.isBidRequestValid(bannerRequest)).to.be.true
})

it('should return false if any parameter missing', function () {
expect(spec.isBidRequestValid(Object.assign(bidRequest, { params: { pubId: null } }))).to.be.false
expect(spec.isBidRequestValid(Object.assign(bidRequest, { params: { medId: null } }))).to.be.false
expect(spec.isBidRequestValid(Object.assign(bidRequest, { params: { zoneId: null } }))).to.be.false
it('should return false if any zone id missing', function () {
expect(spec.isBidRequestValid(Object.assign(bannerRequest, { params: { zoneId: null } }))).to.be.false
})
})

describe('buildRequests', function () {
let req = spec.buildRequests([ bidRequest ], { refererInfo: { } })
let req = spec.buildRequests([ bannerRequest ], { refererInfo: { } })
let rdata

it('should return request object', function () {
Expand All @@ -55,27 +102,17 @@ describe('SmartRTBBidAdapter', function () {
})

it('should include all publisher params', function () {
let r = rdata.imps[0]
expect(r.pub_id !== null && r.med_id !== null && r.zone_id !== null).to.be.true
expect(rdata.imps[0].zone_id !== null).to.be.true
})

it('should include media types', function () {
expect(rdata.imps[0].media_types !== null).to.be.true
})
})

describe('interpretResponse', function () {
it('should form compliant bid object response', function () {
let res = {
body: {
bids: [{
bid_id: '123',
cpm: 1.23,
w: 300,
h: 250,
html: '<b>deadbeef</b>',
crid: 'crid'
}]
}
}

let ir = spec.interpretResponse(res, bidRequest)
it('should form compliant banner bid object response', function () {
let ir = spec.interpretResponse(br, bannerRequest)

expect(ir.length).to.equal(1)

Expand All @@ -89,18 +126,33 @@ describe('SmartRTBBidAdapter', function () {
en.creativeId != null
).to.be.true
})
it('should form compliant video object response', function () {
let ir = spec.interpretResponse(vr, videoRequest)

expect(ir.length).to.equal(1)

let en = ir[0]

expect(en.requestId != null &&
en.cpm != null && typeof en.cpm === 'number' &&
en.width != null && typeof en.width === 'number' &&
en.height != null && typeof en.height === 'number' &&
(en.vastUrl != null || en.vastXml != null) &&
en.creativeId != null
).to.be.true
})
})

describe('getUserSyncs', function () {
it('should return iframe sync', function () {
let sync = spec.getUserSyncs({ iframeEnabled: true })
let sync = spec.getUserSyncs({ iframeEnabled: true }, [br])
expect(sync.length).to.equal(1)
expect(sync[0].type === 'iframe')
expect(typeof sync[0].url === 'string')
})

it('should return pixel sync', function () {
let sync = spec.getUserSyncs({ pixelEnabled: true })
let sync = spec.getUserSyncs({ pixelEnabled: true }, [br])
expect(sync.length).to.equal(1)
expect(sync[0].type === 'image')
expect(typeof sync[0].url === 'string')
Expand Down

0 comments on commit b3371df

Please sign in to comment.