Skip to content
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

Kueez RTB Bid Adapter: added support for video media type #9326

Merged
merged 1 commit into from
Dec 29, 2022
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
29 changes: 21 additions & 8 deletions modules/kueezRtbBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } from '../src/utils.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER } from '../src/mediaTypes.js';
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { getStorageManager } from '../src/storageManager.js';

const GVLID = 1165;
Expand Down Expand Up @@ -55,7 +55,7 @@ function isBidRequestValid(bid) {
}

function buildRequest(bid, topWindowUrl, sizes, bidderRequest) {
const { params, bidId, userId, adUnitCode, schain } = bid;
const { params, bidId, userId, adUnitCode, schain, mediaTypes } = bid;
let { bidFloor, ext } = params;
const hashUrl = hashCode(topWindowUrl);
const uniqueDealId = getUniqueDealId(hashUrl);
Expand Down Expand Up @@ -89,7 +89,8 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) {
bidderVersion: BIDDER_VERSION,
prebidVersion: '$prebid.version$',
res: `${screen.width}x${screen.height}`,
schain: schain
schain: schain,
mediaTypes: mediaTypes
};

appendUserIdsToRequestPayload(data, userId);
Expand Down Expand Up @@ -167,11 +168,12 @@ function interpretResponse(serverResponse, request) {

try {
results.forEach(result => {
const { creativeId, ad, price, exp, width, height, currency, advertiserDomains } = result;
const { creativeId, ad, price, exp, width, height, currency, advertiserDomains, mediaType = BANNER } = result;
if (!ad || !price) {
return;
}
output.push({

const response = {
requestId: bidId,
cpm: price,
width: width,
Expand All @@ -180,11 +182,22 @@ function interpretResponse(serverResponse, request) {
currency: currency || CURRENCY,
netRevenue: true,
ttl: exp || TTL_SECONDS,
ad: ad,
meta: {
advertiserDomains: advertiserDomains || []
}
})
};

if (mediaType === BANNER) {
Object.assign(response, {
ad: ad,
});
} else {
Object.assign(response, {
vastXml: ad,
mediaType: VIDEO
});
}
output.push(response);
});
return output;
} catch (e) {
Expand Down Expand Up @@ -268,7 +281,7 @@ export const spec = {
code: BIDDER_CODE,
version: BIDDER_VERSION,
gvlid: GVLID,
supportedMediaTypes: [BANNER],
supportedMediaTypes: [BANNER, VIDEO],
isBidRequestValid,
buildRequests,
interpretResponse,
Expand Down
171 changes: 147 additions & 24 deletions test/spec/modules/kueezRtbBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {expect} from 'chai';
import { expect } from 'chai';
import {
spec as adapter,
SUPPORTED_ID_SYSTEMS,
Expand All @@ -13,8 +13,9 @@ import {
getUniqueDealId,
} from 'modules/kueezRtbBidAdapter.js';
import * as utils from 'src/utils.js';
import {version} from 'package.json';
import {useFakeTimers} from 'sinon';
import { version } from 'package.json';
import { useFakeTimers } from 'sinon';
import { BANNER, VIDEO } from '../../../src/mediaTypes';

const SUB_DOMAIN = 'exchange';

Expand All @@ -36,9 +37,42 @@ const BID = {
'sizes': [[300, 250], [300, 600]],
'bidderRequestId': '1fdb5ff1b6eaa7',
'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a',
'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc'
'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc',
'mediaTypes': [BANNER]
};

const VIDEO_BID = {
'bidId': '2d52001cabd527',
'adUnitCode': '63550ad1ff6642d368cba59dh5884270560',
'bidderRequestId': '12a8ae9ada9c13',
'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee',
'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc',
'params': {
'subDomain': SUB_DOMAIN,
'cId': '635509f7ff6642d368cb9837',
'pId': '59ac17c192832d0011283fe3',
'bidFloor': 0.1
},
'sizes': [[545, 307]],
'mediaTypes': {
'video': {
'playerSize': [[545, 307]],
'context': 'instream',
'mimes': [
'video/mp4',
'application/javascript'
],
'protocols': [2, 3, 5, 6],
'maxduration': 60,
'minduration': 0,
'startdelay': 0,
'linearity': 1,
'api': [2],
'placement': 1
}
}
}

const BIDDER_REQUEST = {
'gdprConsent': {
'consentString': 'consent_string',
Expand Down Expand Up @@ -73,6 +107,23 @@ const SERVER_RESPONSE = {
}
};

const VIDEO_SERVER_RESPONSE = {
body: {
'cid': '635509f7ff6642d368cb9837',
'results': [{
'ad': '<VAST version=\"3.0\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"></VAST>',
'advertiserDomains': ['kueezrtb.com'],
'exp': 60,
'width': 545,
'height': 307,
'mediaType': 'video',
'creativeId': '12610997325162499419',
'price': 2,
'cookies': []
}]
}
};

const REQUEST = {
data: {
width: 300,
Expand All @@ -83,7 +134,7 @@ const REQUEST = {

function getTopWindowQueryParams() {
try {
const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true});
const parsedUrl = utils.parseUrl(window.top.document.URL, { decodeSearchAsString: true });
return parsedUrl.search;
} catch (e) {
return '';
Expand Down Expand Up @@ -111,6 +162,11 @@ describe('KueezRtbBidAdapter', function () {
it('exists and is a string', function () {
expect(adapter.code).to.exist.and.to.be.a('string');
});

it('exists and contains media types', function () {
expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2);
expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]);
});
});

describe('validate bid requests', function () {
Expand Down Expand Up @@ -155,7 +211,53 @@ describe('KueezRtbBidAdapter', function () {
sandbox.stub(Date, 'now').returns(1000);
});

it('should build request for each size', function () {
it('should build video request', function () {
const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page);
const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST);
expect(requests).to.have.length(1);
expect(requests[0]).to.deep.equal({
method: 'POST',
url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`,
data: {
adUnitCode: '63550ad1ff6642d368cba59dh5884270560',
bidFloor: 0.1,
bidId: '2d52001cabd527',
bidderVersion: adapter.version,
cb: 1000,
gdpr: 1,
gdprConsent: 'consent_string',
usPrivacy: 'consent_string',
prebidVersion: version,
publisherId: '59ac17c192832d0011283fe3',
url: 'https%3A%2F%2Fwww.greatsite.com',
referrer: 'https://www.somereferrer.com',
res: `${window.top.screen.width}x${window.top.screen.height}`,
schain: VIDEO_BID.schain,
sizes: ['545x307'],
uniqueDealId: `${hashUrl}_${Date.now().toString()}`,
uqs: getTopWindowQueryParams(),
mediaTypes: {
video: {
api: [2],
context: 'instream',
linearity: 1,
maxduration: 60,
mimes: [
'video/mp4',
'application/javascript'
],
minduration: 0,
placement: 1,
playerSize: [[545, 307]],
protocols: [2, 3, 5, 6],
startdelay: 0
}
}
}
});
});

it('should build banner request for each size', function () {
const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page);
const requests = adapter.buildRequests([BID], BIDDER_REQUEST);
expect(requests).to.have.length(1);
Expand All @@ -179,6 +281,7 @@ describe('KueezRtbBidAdapter', function () {
prebidVersion: version,
schain: BID.schain,
res: `${window.top.screen.width}x${window.top.screen.height}`,
mediaTypes: [BANNER],
uqs: getTopWindowQueryParams(),
'ext.param1': 'loremipsum',
'ext.param2': 'dolorsitamet',
Expand All @@ -193,7 +296,7 @@ describe('KueezRtbBidAdapter', function () {
});
describe('getUserSyncs', function () {
it('should have valid user sync with iframeEnabled', function () {
const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]);
const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]);

expect(result).to.deep.equal([{
type: 'iframe',
Expand All @@ -202,15 +305,15 @@ describe('KueezRtbBidAdapter', function () {
});

it('should have valid user sync with cid on response', function () {
const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]);
const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]);
expect(result).to.deep.equal([{
type: 'iframe',
url: 'https://sync.kueezrtb.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy='
}]);
});

it('should have valid user sync with pixelEnabled', function () {
const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]);
const result = adapter.getUserSyncs({ pixelEnabled: true }, [SERVER_RESPONSE]);

expect(result).to.deep.equal([{
'url': 'https://sync.kueezrtb.com/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=',
Expand All @@ -226,16 +329,16 @@ describe('KueezRtbBidAdapter', function () {
});

it('should return empty array when there is no ad', function () {
const responses = adapter.interpretResponse({price: 1, ad: ''});
const responses = adapter.interpretResponse({ price: 1, ad: '' });
expect(responses).to.be.empty;
});

it('should return empty array when there is no price', function () {
const responses = adapter.interpretResponse({price: null, ad: 'great ad'});
const responses = adapter.interpretResponse({ price: null, ad: 'great ad' });
expect(responses).to.be.empty;
});

it('should return an array of interpreted responses', function () {
it('should return an array of interpreted banner responses', function () {
const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST);
expect(responses).to.have.length(1);
expect(responses[0]).to.deep.equal({
Expand All @@ -254,6 +357,26 @@ describe('KueezRtbBidAdapter', function () {
});
});

it('should return an array of interpreted video responses', function () {
const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST);
expect(responses).to.have.length(1);
expect(responses[0]).to.deep.equal({
requestId: '2d52001cabd527',
cpm: 2,
width: 545,
height: 307,
mediaType: 'video',
creativeId: '12610997325162499419',
currency: 'USD',
netRevenue: true,
ttl: 60,
vastXml: '<VAST version=\"3.0\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"></VAST>',
meta: {
advertiserDomains: ['kueezrtb.com']
}
});
});

it('should take default TTL', function () {
const serverResponse = utils.deepClone(SERVER_RESPONSE);
delete serverResponse.body.results[0].exp;
Expand All @@ -271,11 +394,11 @@ describe('KueezRtbBidAdapter', function () {
const userId = (function () {
switch (idSystemProvider) {
case 'lipb':
return {lipbid: id};
return { lipbid: id };
case 'parrableId':
return {eid: id};
return { eid: id };
case 'id5id':
return {uid: id};
return { uid: id };
default:
return id;
}
Expand All @@ -294,18 +417,18 @@ describe('KueezRtbBidAdapter', function () {

describe('alternate param names extractors', function () {
it('should return undefined when param not supported', function () {
const cid = extractCID({'c_id': '1'});
const pid = extractPID({'p_id': '1'});
const subDomain = extractSubDomain({'sub_domain': 'prebid'});
const cid = extractCID({ 'c_id': '1' });
const pid = extractPID({ 'p_id': '1' });
const subDomain = extractSubDomain({ 'sub_domain': 'prebid' });
expect(cid).to.be.undefined;
expect(pid).to.be.undefined;
expect(subDomain).to.be.undefined;
});

it('should return value when param supported', function () {
const cid = extractCID({'cID': '1'});
const pid = extractPID({'Pid': '2'});
const subDomain = extractSubDomain({'subDOMAIN': 'prebid'});
const cid = extractCID({ 'cID': '1' });
const pid = extractPID({ 'Pid': '2' });
const subDomain = extractSubDomain({ 'subDOMAIN': 'prebid' });
expect(cid).to.be.equal('1');
expect(pid).to.be.equal('2');
expect(subDomain).to.be.equal('prebid');
Expand Down Expand Up @@ -365,7 +488,7 @@ describe('KueezRtbBidAdapter', function () {
now
});
setStorageItem('myKey', 2020);
const {value, created} = getStorageItem('myKey');
const { value, created } = getStorageItem('myKey');
expect(created).to.be.equal(now);
expect(value).to.be.equal(2020);
expect(typeof value).to.be.equal('number');
Expand All @@ -381,8 +504,8 @@ describe('KueezRtbBidAdapter', function () {
});

it('should parse JSON value', function () {
const data = JSON.stringify({event: 'send'});
const {event} = tryParseJSON(data);
const data = JSON.stringify({ event: 'send' });
const { event } = tryParseJSON(data);
expect(event).to.be.equal('send');
});

Expand Down