-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
AdDefend Bid Adapter: new bid adapter #6450
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 |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import {registerBidder} from '../src/adapters/bidderFactory.js'; | ||
|
||
const BIDDER_CODE = 'addefend'; | ||
|
||
export const spec = { | ||
code: BIDDER_CODE, | ||
hostname: 'https://addefend-platform.com', | ||
|
||
getHostname() { | ||
return this.hostname; | ||
}, | ||
isBidRequestValid: function(bid) { | ||
return (bid.sizes !== undefined && bid.bidId !== undefined && bid.params !== undefined && | ||
(bid.params.pageId !== undefined && (typeof bid.params.pageId === 'string')) && | ||
(bid.params.placementId !== undefined && (typeof bid.params.placementId === 'string'))); | ||
}, | ||
buildRequests: function(validBidRequests, bidderRequest) { | ||
let bid = { | ||
v: $$PREBID_GLOBAL$$.version, | ||
auctionId: false, | ||
pageId: false, | ||
gdpr_consent: bidderRequest.gdprConsent && bidderRequest.gdprConsent.consentString ? bidderRequest.gdprConsent.consentString : '', | ||
referer: bidderRequest.refererInfo.referer, | ||
bids: [], | ||
}; | ||
|
||
for (var i = 0; i < validBidRequests.length; i++) { | ||
let vb = validBidRequests[i]; | ||
let o = vb.params; | ||
bid.auctionId = vb.auctionId; | ||
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. in this loop does it mean that 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. yes, auctionId, pageId and trafficTypes are supposed to be the same for all the requests. |
||
o.bidId = vb.bidId; | ||
o.transactionId = vb.transactionId; | ||
o.sizes = []; | ||
if (o.trafficTypes) { | ||
bid.trafficTypes = o.trafficTypes; | ||
} | ||
delete o.trafficTypes; | ||
|
||
bid.pageId = o.pageId; | ||
delete o.pageId; | ||
|
||
if (vb.sizes && Array.isArray(vb.sizes)) { | ||
for (var j = 0; j < vb.sizes.length; j++) { | ||
let s = vb.sizes[j]; | ||
if (Array.isArray(s) && s.length == 2) { | ||
o.sizes.push(s[0] + 'x' + s[1]); | ||
} | ||
} | ||
} | ||
bid.bids.push(o); | ||
} | ||
return [{ | ||
method: 'POST', | ||
url: this.getHostname() + '/bid', | ||
options: { withCredentials: true }, | ||
data: bid | ||
}]; | ||
}, | ||
interpretResponse: function(serverResponse, request) { | ||
const requiredKeys = ['requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', 'netRevenue', 'currency', 'advertiserDomains']; | ||
const validBidResponses = []; | ||
serverResponse = serverResponse.body; | ||
if (serverResponse && (serverResponse.length > 0)) { | ||
serverResponse.forEach((bid) => { | ||
const bidResponse = {}; | ||
for (const requiredKey of requiredKeys) { | ||
if (!bid.hasOwnProperty(requiredKey)) { | ||
return []; | ||
} | ||
bidResponse[requiredKey] = bid[requiredKey]; | ||
} | ||
validBidResponses.push(bidResponse); | ||
}); | ||
} | ||
return validBidResponses; | ||
} | ||
} | ||
|
||
registerBidder(spec); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Overview | ||
|
||
``` | ||
Module Name: AdDefend Bid Adapter | ||
Module Type: Bidder Adapter | ||
Maintainer: prebid@addefend.com | ||
``` | ||
|
||
# Description | ||
|
||
Module that connects to AdDefend as a demand source. | ||
|
||
## Parameters | ||
| Param | Description | Optional | Default | | ||
| ------------- | ------------- | ----- | ----- | | ||
| pageId | id assigned to the website in the AdDefend system. (ask AdDefend support) | no | - | | ||
| placementId | id of the placement in the AdDefend system. (ask AdDefend support) | no | - | | ||
| trafficTypes | comma seperated list of the following traffic types:<br/>ADBLOCK - user has a activated adblocker<br/>PM - user has firefox private mode activated<br/>NC - user has not given consent<br/>NONE - user traffic is none of the above, this usually means this is a "normal" user.<br/>| yes | ADBLOCK | | ||
|
||
|
||
# Test Parameters | ||
``` | ||
var adUnits = [ | ||
{ | ||
code: 'test-div', | ||
mediaTypes: { | ||
banner: { | ||
sizes: [[970, 250]], // a display size | ||
} | ||
}, | ||
bids: [ | ||
{ | ||
bidder: "addefend", | ||
params: { | ||
pageId: "887", | ||
placementId: "9398", | ||
trafficTypes: "ADBLOCK" | ||
} | ||
} | ||
] | ||
} | ||
]; | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import {expect} from 'chai'; | ||
import {spec} from 'modules/addefendBidAdapter.js'; | ||
|
||
describe('addefendBidAdapter', () => { | ||
const defaultBidRequest = { | ||
bidId: 'd66fa86787e0b0ca900a96eacfd5f0bb', | ||
auctionId: 'ccc4c7cdfe11cfbd74065e6dd28413d8', | ||
transactionId: 'd58851660c0c4461e4aa06344fc9c0c6', | ||
sizes: [[300, 250], [300, 600]], | ||
params: { | ||
pageId: 'stringid1', | ||
placementId: 'stringid2' | ||
} | ||
}; | ||
|
||
const deepClone = function (val) { | ||
return JSON.parse(JSON.stringify(val)); | ||
}; | ||
|
||
const buildRequest = (buildRequest, bidderRequest) => { | ||
if (!Array.isArray(buildRequest)) { | ||
buildRequest = [buildRequest]; | ||
} | ||
|
||
return spec.buildRequests(buildRequest, { | ||
...bidderRequest || {}, | ||
refererInfo: { | ||
referer: 'https://referer.example.com' | ||
} | ||
})[0]; | ||
}; | ||
|
||
describe('isBidRequestValid', () => { | ||
it('should return true when required params found', () => { | ||
const bidRequest = deepClone(defaultBidRequest); | ||
expect(spec.isBidRequestValid(bidRequest)).to.equal(true); | ||
}); | ||
|
||
it('pageId performs type checking', () => { | ||
const bidRequest = deepClone(defaultBidRequest); | ||
bidRequest.params.pageId = 1; // supposed to be a string | ||
expect(spec.isBidRequestValid(bidRequest)).to.equal(false); | ||
}); | ||
|
||
it('placementId performs type checking', () => { | ||
const bidRequest = deepClone(defaultBidRequest); | ||
bidRequest.params.placementId = 1; // supposed to be a string | ||
expect(spec.isBidRequestValid(bidRequest)).to.equal(false); | ||
}); | ||
|
||
it('should return false when required params are not passed', () => { | ||
const bidRequest = deepClone(defaultBidRequest); | ||
delete bidRequest.params; | ||
expect(spec.isBidRequestValid(bidRequest)).to.equal(false); | ||
}); | ||
}); | ||
|
||
describe('buildRequests', () => { | ||
const bidRequest = deepClone(defaultBidRequest); | ||
const request = buildRequest(bidRequest); | ||
|
||
it('sends bid request to endpoint via https using post', () => { | ||
expect(request.method).to.equal('POST'); | ||
expect(request.url.indexOf('https://')).to.equal(0); | ||
expect(request.url).to.equal(`${spec.hostname}/bid`); | ||
}); | ||
|
||
it('contains prebid version parameter', () => { | ||
expect(request.data.v).to.equal($$PREBID_GLOBAL$$.version); | ||
}); | ||
|
||
it('contains correct referer', () => { | ||
expect(request.data.referer).to.equal('https://referer.example.com'); | ||
}); | ||
|
||
it('contains auctionId', () => { | ||
expect(request.data.auctionId).to.equal('ccc4c7cdfe11cfbd74065e6dd28413d8'); | ||
}); | ||
|
||
it('contains pageId', () => { | ||
expect(request.data.pageId).to.equal('stringid1'); | ||
}); | ||
|
||
it('sends correct bid parameters', () => { | ||
const bidRequest = deepClone(defaultBidRequest); | ||
expect(request.data.bids).to.deep.equal([ { | ||
bidId: bidRequest.bidId, | ||
placementId: bidRequest.params.placementId, | ||
sizes: [ '300x250', '300x600' ], | ||
transactionId: 'd58851660c0c4461e4aa06344fc9c0c6' | ||
} ]); | ||
}); | ||
|
||
it('handles empty gdpr object', () => { | ||
const bidRequest = deepClone(defaultBidRequest); | ||
const request = buildRequest(bidRequest, { | ||
gdprConsent: {} | ||
}); | ||
expect(request.data.gdpr_consent).to.be.equal(''); | ||
}); | ||
|
||
it('handles non-existent gdpr object', () => { | ||
const bidRequest = deepClone(defaultBidRequest); | ||
const request = buildRequest(bidRequest, { | ||
gdprConsent: null | ||
}); | ||
expect(request.data.gdpr_consent).to.be.equal(''); | ||
}); | ||
|
||
it('handles properly filled gdpr string', () => { | ||
const bidRequest = deepClone(defaultBidRequest); | ||
const consentString = 'GDPR_CONSENT_STRING'; | ||
const request = buildRequest(bidRequest, { | ||
gdprConsent: { | ||
gdprApplies: true, | ||
consentString: consentString | ||
} | ||
}); | ||
|
||
expect(request.data.gdpr_consent).to.be.equal(consentString); | ||
}); | ||
}); | ||
|
||
describe('interpretResponse', () => { | ||
it('should get correct bid response', () => { | ||
const serverResponse = [ | ||
{ | ||
'width': 300, | ||
'height': 250, | ||
'creativeId': '29681110', | ||
'ad': '<!-- Creative -->', | ||
'cpm': 0.5, | ||
'requestId': 'ccc4c7cdfe11cfbd74065e6dd28413d8', | ||
'ttl': 120, | ||
'netRevenue': true, | ||
'currency': 'EUR', | ||
'advertiserDomains': ['advertiser.example.com'] | ||
} | ||
]; | ||
|
||
const expectedResponse = [ | ||
{ | ||
'requestId': 'ccc4c7cdfe11cfbd74065e6dd28413d8', | ||
'cpm': 0.5, | ||
'creativeId': '29681110', | ||
'width': 300, | ||
'height': 250, | ||
'ttl': 120, | ||
'currency': 'EUR', | ||
'ad': '<!-- Creative -->', | ||
'netRevenue': true, | ||
'advertiserDomains': ['advertiser.example.com'] | ||
} | ||
]; | ||
|
||
const result = spec.interpretResponse({body: serverResponse}); | ||
expect(result.length).to.equal(expectedResponse.length); | ||
Object.keys(expectedResponse[0]).forEach((key) => { | ||
expect(result[0][key]).to.deep.equal(expectedResponse[0][key]); | ||
}); | ||
}); | ||
|
||
it('handles incomplete server response', () => { | ||
const serverResponse = [ | ||
{ | ||
'ad': '<!-- Creative -->', | ||
'cpm': 0.5, | ||
'requestId': 'ccc4c7cdfe11cfbd74065e6dd28413d8', | ||
'ttl': 60 | ||
} | ||
]; | ||
const result = spec.interpretResponse({body: serverResponse}); | ||
|
||
expect(result.length).to.equal(0); | ||
}); | ||
|
||
it('handles nobid responses', () => { | ||
const serverResponse = []; | ||
const result = spec.interpretResponse({body: serverResponse}); | ||
|
||
expect(result.length).to.equal(0); | ||
}); | ||
}); | ||
}); |
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.
are these supposed to be bools?
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.
yes, for the theoretical case that there are no validBidRequests (length==0) the resulting request would send false for auctionId and pageId.