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

Performax adapter #5480

Merged
merged 3 commits into from
Jul 17, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
56 changes: 56 additions & 0 deletions modules/performaxBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {logWarn} from '../src/utils.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';

const CLIENT = 'hellboy:v0.0.1'
const BIDDER_CODE = 'performax';
const BIDDER_SHORT_CODE = 'px';
const ENDPOINT = 'https://dale.performax.cz/hb';

export const spec = {
code: BIDDER_CODE,
aliases: [BIDDER_SHORT_CODE],

isBidRequestValid: function (bid) {
return !!bid.params.slotId;
},

buildUrl: function (validBidRequests, bidderRequest) {
const slotIds = validBidRequests.map(request => request.params.slotId);
let url = [`${ENDPOINT}?slotId[]=${slotIds.join()}`];
url.push('client=' + CLIENT);
url.push('auctionId=' + bidderRequest.auctionId);
return url.join('&');
},

buildRequests: function (validBidRequests, bidderRequest) {
return {
method: 'POST',
url: this.buildUrl(validBidRequests, bidderRequest),
data: {'validBidRequests': validBidRequests, 'bidderRequest': bidderRequest},
options: {contentType: 'application/json'},
}
},

buildHtml: function (ad) {
const keys = Object.keys(ad.data || {});
return ad.code.replace(
new RegExp('\\$(' + keys.join('|') + ')\\$', 'g'),
(matched, key) => ad.data[key] || matched
);
},

interpretResponse: function (serverResponse, request) {
let bidResponses = [];
for (let i = 0; i < serverResponse.body.length; i++) {
const ad = serverResponse.body[i].ad;
if (ad.type === 'empty') {
logWarn(`One of ads is empty (reason=${ad.reason})`);
continue;
}
serverResponse.body[i].ad = this.buildHtml(ad);
bidResponses.push(serverResponse.body[i]);
}
return bidResponses;
}
}
registerBidder(spec);
36 changes: 36 additions & 0 deletions modules/performaxBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Overview

```
Module Name: Performax Bid Adapter
Module Type: Bidder Adapter
Maintainer: development@performax.cz
```

# Description

Connects to Performax exchange for bids.

Performax bid adapter supports Banner.


# Sample Banner Ad Unit: For Publishers

```javascript
var adUnits = [
{
code: 'performax-div',
sizes: [[300, 300]],
bids: [
{
bidder: "performax",
params: {
slotId: 28 // required
}
}
]
}
];
```

Where:
* slotId - id of slot in PX system
274 changes: 274 additions & 0 deletions test/spec/modules/performaxBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
import * as utils from 'src/utils.js';
import { expect } from 'chai';
import { spec } from 'modules/performaxBidAdapter';

describe('PerformaxAdapter', function () {
let bidRequests, bidderRequest;
let serverResponse, serverRequest;

const URL =
'https://dale.performax.cz/hb?slotId[]=3,2&client=hellboy:v0.0.1&auctionId=144b5079-8cbf-49a5-aca7-a68b3296cd6c';

bidRequests = [
{
adUnitCode: 'postbid_iframe',
auctionId: '144b5079-8cbf-49a5-aca7-a68b3296cd6c',
bidId: '2a4332f6b2bc74',
bidRequestsCount: 1,
bidder: 'performax',
bidderRequestId: '1c7d8bf204f11e',
bidderRequestsCount: 1,
bidderWinsCount: 0,
mediaTypes: {
banner: {
sizes: [[300, 300]],
},
},
params: {
slotId: 3,
},
sizes: [[300, 300]],
src: 'client',
transactionId: '14969d09-0068-4d5b-a34e-e35091561dee',
},
{
adUnitCode: 'postbid_iframe2',
auctionId: '144b5079-8cbf-49a5-aca7-a68b3296cd6c',
bidId: '300bb0ac6a156a',
bidRequestsCount: 1,
bidder: 'performax',
bidderRequestId: '1c7d8bf204f11e',
bidderRequestsCount: 1,
bidderWinsCount: 0,
mediaTypes: {
banner: {
sizes: [[300, 300]],
},
},
params: {
slotId: 2,
},
sizes: [[300, 300]],
src: 'client',
transactionId: '107cbebd-8c36-4456-b28c-91a19ba80151',
},
];

bidderRequest = {
auctionId: '144b5079-8cbf-49a5-aca7-a68b3296cd6c',
auctionStart: 1594281941845,
bidderCode: 'performax',
bidderRequestId: '1c7d8bf204f11e',
bids: bidRequests,
refererInfo: {
canonicalUrl: '',
numIframes: 0,
reachedTop: true,
referer: '',
},
stack: [''],
start: 1594281941935,
timeout: 3600,
};

serverResponse = {
body: [
{
ad: {
code: '$SYS_ID$ $VAR_NAME$ rest of the code',
data: {
SYS_ID: 1,
VAR_NAME: 'name',
},
format_id: 2,
id: 11,
size: {
width: 300,
height: 300,
},
tag_ids: [],
type: 'creative',
},
cpm: 30,
creativeId: 'creative:11',
currency: 'CZK',
height: 300,
meta: {
agencyId: 1,
mediaType: 'banner',
},
netRevenue: true,
requestId: '2a4332f6b2bc74',
ttl: 60,
width: 300,
},
{
ad: {
code: '<!-- px empty -->',
reason: 'Slot 2 does not allow HB requests',
type: 'empty',
},
cpm: 0,
creativeId: null,
currency: 'CZK',
height: null,
meta: {
agencyId: null,
mediaType: 'banner',
},
netRevenue: true,
requestId: '1c7d8bf204f11e',
ttl: 60,
width: 300,
},
],
};

serverRequest = {
data: {
bidderRequest: bidderRequest,
validBidRequests: bidRequests,
},
method: 'POST',
options: {
contentType: 'application/json',
},
url: URL,
};

describe('Bid validations', function () {
it('Valid bid', function () {
let validBid = {
bidder: 'performax',
params: {
slotId: 2,
},
},
isValid = spec.isBidRequestValid(validBid);
expect(isValid).to.equal(true);
});

it('Invalid bid: required param is missing', function () {
let invalidBid = {
bidder: 'performax',
params: {
invalidParam: 2,
},
},
isValid = spec.isBidRequestValid(invalidBid);
expect(isValid).to.equal(false);
});
});

describe('Build Url', function () {
it('Should return url', function () {
let url = spec.buildUrl(bidRequests, bidderRequest);
expect(url).to.equal(URL);
});
});

describe('Build Request', function () {
it('Should not modify bidRequests and bidder Requests', function () {
let originalBidRequests = utils.deepClone(bidRequests);
let originalBidderRequest = utils.deepClone(bidderRequest);
let request = spec.buildRequests(bidRequests, bidderRequest);

expect(bidRequests).to.deep.equal(originalBidRequests);
expect(bidderRequest).to.deep.equal(originalBidderRequest);
});

it('Endpoint checking', function () {
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.url).to.equal(URL);
expect(request.method).to.equal('POST');
expect(request.options).to.deep.equal({
contentType: 'application/json',
});
});

it('Request params checking', function () {
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.validBidRequests).to.deep.equal(bidRequests);
expect(request.data.bidderRequest).to.deep.equal(bidderRequest);
});
});

describe('Build Html', function () {
it('Ad with data: should return build html', function () {
let validAd = {
code: '$SYS_ID$ $VAR_NAME$ rest of the code',
data: {
SYS_ID: 1,
VAR_NAME: 'name',
},
format_id: 2,
id: 11,
size: {
width: 300,
height: 300,
},
tag_ids: [],
type: 'creative',
};
let html = spec.buildHtml(validAd);
expect(html).to.equal('1 name rest of the code');
});

it('Ad with partial data: should return html without data change', function () {
let adWithPartialData = {
code: '$SYS_ID$ $VAR_NAME$ rest of the code',
data: {
VAR_NAME: 'name',
},
format_id: 2,
id: 11,
size: {
width: 300,
height: 300,
},
tag_ids: [],
type: 'creative',
};
let html = spec.buildHtml(adWithPartialData);
expect(html).to.equal('$SYS_ID$ name rest of the code');
});

it('Ad without data: should return html without data change', function () {
let adWithoutData = {
code: '$SYS_ID$ $VAR_NAME$ rest of the code',
format_id: 2,
id: 11,
size: {
width: 300,
height: 300,
},
tag_ids: [],
type: 'creative',
};
let html = spec.buildHtml(adWithoutData);
expect(html).to.equal('$SYS_ID$ $VAR_NAME$ rest of the code');
});
});

describe('Interpret Response', function () {
it('Ad without data: should return html without data change', function () {
let ads = spec.interpretResponse(serverResponse, serverRequest);
expect(ads).to.have.length(1);
expect(ads[0]).to.deep.equal({
ad: '1 name rest of the code',
cpm: 30,
creativeId: 'creative:11',
currency: 'CZK',
height: 300,
meta: {
agencyId: 1,
mediaType: 'banner',
},
netRevenue: true,
requestId: '2a4332f6b2bc74',
ttl: 60,
width: 300,
});
});
});
});