Skip to content

Commit 5f37cc1

Browse files
ckbo3hrksa1omon
authored andcommitted
Adkernel adapter minor update (prebid#4000)
* Updated maintainer email * Minor refactoring & more unit tests * Unit tests for new utility function
1 parent 469065b commit 5f37cc1

File tree

5 files changed

+178
-59
lines changed

5 files changed

+178
-59
lines changed

modules/adkernelBidAdapter.js

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,24 @@ export const spec = {
1919
aliases: ['headbidding'],
2020
supportedMediaTypes: [BANNER, VIDEO],
2121
isBidRequestValid: function(bidRequest) {
22-
return 'params' in bidRequest && typeof bidRequest.params.host !== 'undefined' &&
23-
'zoneId' in bidRequest.params && !isNaN(Number(bidRequest.params.zoneId)) &&
24-
bidRequest.mediaTypes && (bidRequest.mediaTypes.banner || bidRequest.mediaTypes.video);
22+
return 'params' in bidRequest &&
23+
typeof bidRequest.params.host !== 'undefined' &&
24+
'zoneId' in bidRequest.params &&
25+
!isNaN(Number(bidRequest.params.zoneId)) &&
26+
bidRequest.params.zoneId > 0 &&
27+
bidRequest.mediaTypes &&
28+
(bidRequest.mediaTypes.banner || bidRequest.mediaTypes.video);
2529
},
2630
buildRequests: function(bidRequests, bidderRequest) {
2731
let impDispatch = dispatchImps(bidRequests, bidderRequest.refererInfo);
28-
const gdprConsent = bidderRequest.gdprConsent;
29-
const auctionId = bidderRequest.auctionId;
32+
const {gdprConsent, auctionId} = bidderRequest;
3033
const requests = [];
3134
Object.keys(impDispatch).forEach(host => {
3235
Object.keys(impDispatch[host]).forEach(zoneId => {
3336
const request = buildRtbRequest(impDispatch[host][zoneId], auctionId, gdprConsent, bidderRequest.refererInfo);
3437
requests.push({
3538
method: 'POST',
36-
url: `${window.location.protocol}//${host}/hb?zone=${Number(zoneId)}&v=${VERSION}`,
39+
url: `${window.location.protocol}//${host}/hb?zone=${zoneId}&v=${VERSION}`,
3740
data: JSON.stringify(request)
3841
});
3942
});
@@ -47,13 +50,12 @@ export const spec = {
4750
}
4851

4952
let rtbRequest = JSON.parse(request.data);
50-
let rtbImps = rtbRequest.imp;
5153
let rtbBids = response.seatbid
5254
.map(seatbid => seatbid.bid)
5355
.reduce((a, b) => a.concat(b), []);
5456

5557
return rtbBids.map(rtbBid => {
56-
let imp = find(rtbImps, imp => imp.id === rtbBid.impid);
58+
let imp = find(rtbRequest.imp, imp => imp.id === rtbBid.impid);
5759
let prBid = {
5860
requestId: rtbBid.impid,
5961
cpm: rtbBid.price,
@@ -119,19 +121,16 @@ function buildImp(bidRequest, secure) {
119121
if (utils.deepAccess(bidRequest, `mediaTypes.banner`)) {
120122
let sizes = canonicalizeSizesArray(bidRequest.mediaTypes.banner.sizes);
121123
imp.banner = {
122-
format: sizes.map(s => ({'w': s[0], 'h': s[1]})),
124+
format: sizes.map(wh => utils.parseGPTSingleSizeArrayToRtbSize(wh)),
123125
topframe: 0
124126
};
125127
} else if (utils.deepAccess(bidRequest, 'mediaTypes.video')) {
126128
let size = canonicalizeSizesArray(bidRequest.mediaTypes.video.playerSize)[0];
127-
imp.video = {
128-
w: size[0],
129-
h: size[1]
130-
};
129+
imp.video = utils.parseGPTSingleSizeArrayToRtbSize(size);
131130
if (bidRequest.params.video) {
132131
Object.keys(bidRequest.params.video)
133-
.filter(param => includes(VIDEO_TARGETING, param))
134-
.forEach(param => imp.video[param] = bidRequest.params.video[param]);
132+
.filter(key => includes(VIDEO_TARGETING, key))
133+
.forEach(key => imp.video[key] = bidRequest.params.video[key]);
135134
}
136135
}
137136
if (secure) {
@@ -198,18 +197,18 @@ function getLanguage() {
198197
*/
199198
function createSite(refInfo) {
200199
let url = parseUrl(refInfo.referer);
201-
let result = {
200+
let site = {
202201
'domain': url.hostname,
203202
'page': url.protocol + '://' + url.hostname + url.pathname
204203
};
205204
if (self === top && document.referrer) {
206-
result.ref = document.referrer;
205+
site.ref = document.referrer;
207206
}
208207
let keywords = document.getElementsByTagName('meta')['keywords'];
209208
if (keywords && keywords.content) {
210-
result.keywords = keywords.content;
209+
site.keywords = keywords.content;
211210
}
212-
return result;
211+
return site;
213212
}
214213

215214
/**

modules/adkernelBidAdapter.md

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
```
44
Module Name: AdKernel Bidder Adapter
55
Module Type: Bidder Adapter
6-
Maintainer: denis@adkernel.com
6+
Maintainer: prebid-dev@adkernel.com
77
```
88

99
# Description
@@ -14,32 +14,38 @@ Banner and video formats are supported.
1414

1515
# Test Parameters
1616
```
17-
var adUnits = [
18-
{
19-
code: 'banner-ad-div',
20-
sizes: [[300, 250]], // banner size
21-
bids: [
22-
{
23-
bidder: 'adkernel',
24-
params: {
25-
zoneId: '30164', //required parameter
26-
host: 'cpm.metaadserving.com' //required parameter
27-
}
28-
}
29-
]
30-
}, {
31-
code: 'video-ad-player',
32-
sizes: [640, 480], // video player size
33-
bids: [
34-
{
35-
bidder: 'adkernel',
36-
mediaType : 'video',
37-
params: {
38-
zoneId: '30164', //required parameter
39-
host: 'cpm.metaadserving.com' //required parameter
40-
}
41-
}
42-
]
43-
}
44-
];
17+
var adUnits = [{
18+
code: 'banner-ad-div',
19+
mediaTypes: {
20+
banner: {
21+
sizes: [[300, 250]], // banner size
22+
}
23+
},
24+
bids: [
25+
{
26+
bidder: 'adkernel',
27+
params: {
28+
zoneId: '30164', //required parameter
29+
host: 'cpm.metaadserving.com' //required parameter
30+
}
31+
}
32+
]
33+
}, {
34+
code: 'video-ad-player',
35+
mediaTypes: {
36+
video: {
37+
context: 'instream', // or 'outstream'
38+
playerSize: [640, 480] // video player size
39+
}
40+
},
41+
bids: [
42+
{
43+
bidder: 'adkernel',
44+
params: {
45+
zoneId: '30164', //required parameter
46+
host: 'cpm.metaadserving.com' //required parameter
47+
}
48+
}
49+
]
50+
}];
4551
```

src/utils.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,27 @@ export function parseSizesInput(sizeObj) {
219219
return parsedSizes;
220220
}
221221

222-
// parse a GPT style sigle size array, (i.e [300,250])
222+
// Parse a GPT style single size array, (i.e [300, 250])
223223
// into an AppNexus style string, (i.e. 300x250)
224224
export function parseGPTSingleSizeArray(singleSize) {
225-
// if we aren't exactly 2 items in this array, it is invalid
226-
if (isArray(singleSize) && singleSize.length === 2 && (!isNaN(singleSize[0]) && !isNaN(singleSize[1]))) {
225+
if (isValidGPTSingleSize(singleSize)) {
227226
return singleSize[0] + 'x' + singleSize[1];
228227
}
229228
}
230229

230+
// Parse a GPT style single size array, (i.e [300, 250])
231+
// into OpenRTB-compatible (imp.banner.w/h, imp.banner.format.w/h, imp.video.w/h) object(i.e. {w:300, h:250})
232+
export function parseGPTSingleSizeArrayToRtbSize(singleSize) {
233+
if (isValidGPTSingleSize(singleSize)) {
234+
return {w: singleSize[0], h: singleSize[1]};
235+
}
236+
}
237+
238+
function isValidGPTSingleSize(singleSize) {
239+
// if we aren't exactly 2 items in this array, it is invalid
240+
return isArray(singleSize) && singleSize.length === 2 && (!isNaN(singleSize[0]) && !isNaN(singleSize[1]));
241+
}
242+
231243
/**
232244
* @deprecated This function will be removed soon. Use http://prebid.org/dev-docs/bidder-adaptor.html#referrers
233245
*/

test/spec/modules/adkernelBidAdapter_spec.js

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,59 +5,71 @@ import * as utils from 'src/utils';
55
describe('Adkernel adapter', function () {
66
const bid1_zone1 = {
77
bidder: 'adkernel',
8-
bidId: 'Bid_01',
98
params: {zoneId: 1, host: 'rtb.adkernel.com'},
109
adUnitCode: 'ad-unit-1',
10+
bidId: 'Bid_01',
11+
bidderRequestId: 'req-001',
12+
auctionId: 'auc-001',
1113
mediaTypes: {
1214
banner: {
1315
sizes: [[300, 250], [300, 200]]
1416
}
1517
}
1618
}, bid2_zone2 = {
1719
bidder: 'adkernel',
18-
bidId: 'Bid_02',
1920
params: {zoneId: 2, host: 'rtb.adkernel.com'},
2021
adUnitCode: 'ad-unit-2',
22+
bidId: 'Bid_02',
23+
bidderRequestId: 'req-001',
24+
auctionId: 'auc-001',
2125
mediaTypes: {
2226
banner: {
23-
sizes: [728, 90]
27+
sizes: [[728, 90]]
2428
}
2529
}
2630
}, bid3_host2 = {
2731
bidder: 'adkernel',
28-
bidId: 'Bid_02',
2932
params: {zoneId: 1, host: 'rtb-private.adkernel.com'},
3033
adUnitCode: 'ad-unit-2',
34+
bidId: 'Bid_02',
35+
bidderRequestId: 'req-001',
36+
auctionId: 'auc-001',
3137
mediaTypes: {
3238
banner: {
3339
sizes: [[728, 90]]
3440
}
3541
}
3642
}, bid_without_zone = {
3743
bidder: 'adkernel',
38-
bidId: 'Bid_W',
3944
params: {host: 'rtb-private.adkernel.com'},
4045
adUnitCode: 'ad-unit-1',
46+
bidId: 'Bid_W',
47+
bidderRequestId: 'req-002',
48+
auctionId: 'auc-002',
4149
mediaTypes: {
4250
banner: {
4351
sizes: [[728, 90]]
4452
}
4553
}
4654
}, bid_without_host = {
4755
bidder: 'adkernel',
48-
bidId: 'Bid_W',
4956
params: {zoneId: 1},
5057
adUnitCode: 'ad-unit-1',
58+
bidId: 'Bid_W',
59+
bidderRequestId: 'req-002',
60+
auctionId: 'auc-002',
5161
mediaTypes: {
5262
banner: {
5363
sizes: [[728, 90]]
5464
}
5565
}
5666
}, bid_with_wrong_zoneId = {
5767
bidder: 'adkernel',
58-
bidId: 'Bid_02',
5968
params: {zoneId: 'wrong id', host: 'rtb.adkernel.com'},
6069
adUnitCode: 'ad-unit-2',
70+
bidId: 'Bid_02',
71+
bidderRequestId: 'req-002',
72+
auctionId: 'auc-002',
6173
mediaTypes: {
6274
banner: {
6375
sizes: [[728, 90]]
@@ -72,7 +84,8 @@ describe('Adkernel adapter', function () {
7284
sizes: [[640, 480]],
7385
params: {
7486
zoneId: 1,
75-
host: 'rtb.adkernel.com'
87+
host: 'rtb.adkernel.com',
88+
video: {api: [1, 2]}
7689
},
7790
mediaTypes: {
7891
video: {
@@ -81,6 +94,19 @@ describe('Adkernel adapter', function () {
8194
}
8295
},
8396
adUnitCode: 'ad-unit-1'
97+
}, bid_multiformat = {
98+
bidder: 'adkernel',
99+
params: {zoneId: 1, host: 'rtb.adkernel.com'},
100+
mediaTypes: {
101+
banner: {sizes: [[300, 250], [300, 200]]},
102+
video: {context: 'instream', playerSize: [[640, 480]]}
103+
},
104+
adUnitCode: 'ad-unit-1',
105+
transactionId: 'f82c64b8-c602-42a4-9791-4a268f6559ed',
106+
sizes: [[300, 250], [300, 200]],
107+
bidId: 'Bid_01',
108+
bidderRequestId: 'req-001',
109+
auctionId: 'auc-001'
84110
};
85111

86112
const bidResponse1 = {
@@ -183,6 +209,11 @@ describe('Adkernel adapter', function () {
183209
expect(bidRequest.imp[0]).to.have.property('banner');
184210
});
185211

212+
it('should have id', function () {
213+
expect(bidRequest.imp[0]).to.have.property('id');
214+
expect(bidRequest.imp[0].id).to.be.eql('Bid_01');
215+
});
216+
186217
it('should have w/h', function () {
187218
expect(bidRequest.imp[0].banner).to.have.property('format');
188219
expect(bidRequest.imp[0].banner.format).to.be.eql([{w: 300, h: 250}, {w: 300, h: 200}]);
@@ -257,6 +288,27 @@ describe('Adkernel adapter', function () {
257288
it('should have tagid', function () {
258289
expect(bidRequests[0].imp[0]).to.have.property('tagid', 'ad-unit-1');
259290
});
291+
292+
it('should have openrtb video impression parameters', function() {
293+
expect(bidRequests[0].imp[0].video).to.have.property('api');
294+
expect(bidRequests[0].imp[0].video.api).to.be.eql([1, 2]);
295+
});
296+
});
297+
298+
describe('multiformat request building', function () {
299+
let _, bidRequests;
300+
before(function () {
301+
[_, bidRequests] = buildRequest([bid_multiformat]);
302+
});
303+
it('should contain single request', function () {
304+
expect(bidRequests).to.have.length(1);
305+
expect(bidRequests[0].imp).to.have.length(1);
306+
});
307+
it('should contain banner-only impression', function () {
308+
expect(bidRequests[0].imp).to.have.length(1);
309+
expect(bidRequests[0].imp[0]).to.have.property('banner');
310+
expect(bidRequests[0].imp[0]).to.not.have.property('video');
311+
});
260312
});
261313

262314
describe('requests routing', function () {

0 commit comments

Comments
 (0)