forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding Scaleable Analytics Adapter (prebid#3846)
* Adding Scaleable Analytics Adapter * Removed commented out code
- Loading branch information
1 parent
99ea60b
commit 72caf98
Showing
3 changed files
with
309 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/* COPYRIGHT SCALEABLE LLC 2019 */ | ||
|
||
import { ajax } from '../src/ajax'; | ||
import CONSTANTS from '../src/constants.json'; | ||
import adapter from '../src/AnalyticsAdapter'; | ||
import adapterManager from '../src/adapterManager'; | ||
import * as utils from '../src/utils'; | ||
|
||
const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; | ||
const AUCTION_INIT = CONSTANTS.EVENTS.AUCTION_INIT; | ||
const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE; | ||
const BID_WON = CONSTANTS.EVENTS.BID_WON; | ||
const AUCTION_END = CONSTANTS.EVENTS.AUCTION_END; | ||
|
||
const URL = 'https://auction.scaleable.ai/'; | ||
const ANALYTICS_TYPE = 'endpoint'; | ||
|
||
let auctionData = {}; | ||
|
||
let scaleableAnalytics = Object.assign({}, | ||
adapter({ | ||
URL, | ||
ANALYTICS_TYPE | ||
}), | ||
{ | ||
// Override AnalyticsAdapter functions by supplying custom methods | ||
track({ eventType, args }) { | ||
switch (eventType) { | ||
case AUCTION_INIT: | ||
onAuctionInit(args); | ||
break; | ||
case AUCTION_END: | ||
onAuctionEnd(args); | ||
break; | ||
case BID_WON: | ||
onBidWon(args); | ||
break; | ||
case BID_RESPONSE: | ||
onBidResponse(args); | ||
break; | ||
case BID_TIMEOUT: | ||
onBidTimeout(args); | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
); | ||
|
||
scaleableAnalytics.config = {}; | ||
scaleableAnalytics.originEnableAnalytics = scaleableAnalytics.enableAnalytics; | ||
scaleableAnalytics.enableAnalytics = config => { | ||
scaleableAnalytics.config = config; | ||
|
||
scaleableAnalytics.originEnableAnalytics(config); | ||
|
||
scaleableAnalytics.enableAnalytics = function _enable() { | ||
return utils.logMessage(`Analytics adapter for "${global}" already enabled, unnecessary call to \`enableAnalytics\`.`); | ||
}; | ||
} | ||
|
||
scaleableAnalytics.getAuctionData = () => { | ||
return auctionData; | ||
}; | ||
|
||
const sendDataToServer = data => ajax(URL, () => {}, JSON.stringify(data)); | ||
|
||
// Track auction initiated | ||
const onAuctionInit = args => { | ||
const config = scaleableAnalytics.config || {options: {}}; | ||
|
||
for (let idx = args.adUnitCodes.length; idx--;) { | ||
const data = { | ||
event: 'request', | ||
site: config.options.site, | ||
adunit: args.adUnitCodes[idx] | ||
}; | ||
|
||
sendDataToServer(data); | ||
} | ||
} | ||
|
||
// Handle all events besides requests and wins | ||
const onAuctionEnd = args => { | ||
for (let adunit in auctionData) { | ||
sendDataToServer(auctionData[adunit]); | ||
} | ||
} | ||
|
||
// Bid Win Events occur after auction end | ||
const onBidWon = args => { | ||
const config = scaleableAnalytics.config || {options: {}}; | ||
|
||
const data = { | ||
event: 'win', | ||
site: config.options.site, | ||
adunit: args.adUnitCode, | ||
code: args.bidderCode, | ||
cpm: args.cpm, | ||
ttr: args.timeToRespond | ||
}; | ||
|
||
sendDataToServer(data); | ||
} | ||
|
||
const onBidResponse = args => { | ||
const config = scaleableAnalytics.config || {options: {}}; | ||
|
||
if (!auctionData[args.adUnitCode]) { | ||
auctionData[args.adUnitCode] = { | ||
event: 'bids', | ||
bids: [], | ||
adunit: args.adUnitCode, | ||
site: config.options.site | ||
}; | ||
} | ||
|
||
const currBidData = { | ||
code: args.bidderCode, | ||
cpm: args.cpm, | ||
ttr: args.timeToRespond | ||
}; | ||
|
||
auctionData[args.adUnitCode].bids.push(currBidData); | ||
} | ||
|
||
const onBidTimeout = args => { | ||
const config = scaleableAnalytics.config || {options: {}}; | ||
|
||
for (let i = args.length; i--;) { | ||
let currObj = args[i]; | ||
|
||
if (!auctionData[currObj.adUnitCode]) { | ||
auctionData[currObj.adUnitCode] = { | ||
event: 'bids', | ||
bids: [], | ||
timeouts: [], | ||
adunit: currObj.adUnitCode, | ||
site: config.options.site | ||
}; | ||
} | ||
|
||
auctionData[currObj.adUnitCode].timeouts.push(currObj.bidder); | ||
} | ||
} | ||
|
||
adapterManager.registerAnalyticsAdapter({ | ||
adapter: scaleableAnalytics, | ||
code: 'scaleable' | ||
}) | ||
|
||
export default scaleableAnalytics; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Overview | ||
|
||
Module Name: Scaleable Analytics Adapter | ||
Module Type: Analytics Adapter | ||
Maintainer: [email protected] | ||
|
||
# Description | ||
|
||
Analytics adapter for scaleable.ai. Contact [email protected] for more information or to sign up for analytics. | ||
|
||
# Implementation Code | ||
|
||
``` | ||
pbjs.enableAnalytics({ | ||
provider: 'scaleable', | ||
options: { | ||
site: '' // Contact Scaleable to receive your unique site id | ||
} | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import scaleableAnalytics from 'modules/scaleableAnalyticsAdapter'; | ||
import { expect } from 'chai'; | ||
import events from 'src/events'; | ||
import CONSTANTS from 'src/constants.json'; | ||
import adapterManager from 'src/adapterManager'; | ||
|
||
const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; | ||
const AUCTION_INIT = CONSTANTS.EVENTS.AUCTION_INIT; | ||
const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE; | ||
const BID_WON = CONSTANTS.EVENTS.BID_WON; | ||
const AUCTION_END = CONSTANTS.EVENTS.AUCTION_END; | ||
|
||
describe('Scaleable Analytics Adapter', function() { | ||
const MOCK_DATA = { | ||
adUnitCode: '12345', | ||
site: '5c4fab7a829e955d6c265e72', | ||
bidResponse: { | ||
adUnitCode: '12345', | ||
bidderCode: 'test-code', | ||
cpm: 3.14, | ||
timeToRespond: 285 | ||
}, | ||
bidTimeout: [ | ||
{ | ||
adUnitCode: '67890', | ||
bidder: 'test-code' | ||
} | ||
] | ||
}; | ||
|
||
MOCK_DATA.expectedBidResponse = { | ||
event: 'bids', | ||
bids: [{ | ||
code: MOCK_DATA.bidResponse.bidderCode, | ||
cpm: MOCK_DATA.bidResponse.cpm, | ||
ttr: MOCK_DATA.bidResponse.timeToRespond | ||
}], | ||
adunit: MOCK_DATA.adUnitCode, | ||
site: MOCK_DATA.site | ||
}; | ||
|
||
MOCK_DATA.expectedBidTimeout = { | ||
event: 'bids', | ||
bids: [], | ||
timeouts: [MOCK_DATA.bidTimeout[0].bidder], | ||
adunit: MOCK_DATA.bidTimeout[0].adUnitCode, | ||
site: MOCK_DATA.site | ||
}; | ||
|
||
let xhr; | ||
let requests; | ||
|
||
before(function() { | ||
xhr = sinon.useFakeXMLHttpRequest(); | ||
xhr.onCreate = request => requests.push(request); | ||
}); | ||
|
||
after(function() { | ||
xhr.restore(); | ||
}); | ||
|
||
describe('Event Handling', function() { | ||
beforeEach(function() { | ||
requests = []; | ||
sinon.stub(events, 'getEvents').returns([]); | ||
|
||
scaleableAnalytics.enableAnalytics({ | ||
provider: 'scaleable', | ||
options: { | ||
site: MOCK_DATA.site | ||
} | ||
}); | ||
}); | ||
|
||
afterEach(function() { | ||
events.getEvents.restore(); | ||
scaleableAnalytics.disableAnalytics(); | ||
}); | ||
|
||
it('should handle the auction init event', function(done) { | ||
events.emit(AUCTION_INIT, { | ||
adUnitCodes: [MOCK_DATA.adUnitCode] | ||
}); | ||
|
||
const result = JSON.parse(requests[0].requestBody); | ||
expect(result).to.deep.equal({ | ||
event: 'request', | ||
site: MOCK_DATA.site, | ||
adunit: MOCK_DATA.adUnitCode | ||
}); | ||
|
||
done(); | ||
}); | ||
|
||
it('should handle the bid response event', function() { | ||
events.emit(BID_RESPONSE, MOCK_DATA.bidResponse); | ||
|
||
const actual = scaleableAnalytics.getAuctionData(); | ||
|
||
expect(actual[MOCK_DATA.adUnitCode]).to.deep.equal(MOCK_DATA.expectedBidResponse); | ||
}); | ||
|
||
it('should handle the bid timeout event', function() { | ||
events.emit(BID_TIMEOUT, MOCK_DATA.bidTimeout); | ||
|
||
const actual = scaleableAnalytics.getAuctionData(); | ||
|
||
expect(actual[MOCK_DATA.bidTimeout[0].adUnitCode]).to.deep.equal(MOCK_DATA.expectedBidTimeout); | ||
}); | ||
|
||
it('should handle the bid won event', function(done) { | ||
events.emit(BID_WON, MOCK_DATA.bidResponse); | ||
|
||
const result = JSON.parse(requests[0].requestBody); | ||
expect(result).to.deep.equal({ | ||
adunit: MOCK_DATA.adUnitCode, | ||
code: MOCK_DATA.bidResponse.bidderCode, | ||
cpm: MOCK_DATA.bidResponse.cpm, | ||
ttr: MOCK_DATA.bidResponse.timeToRespond, | ||
event: 'win', | ||
site: MOCK_DATA.site | ||
}); | ||
|
||
done(); | ||
}); | ||
|
||
it('should handle the auction end event', function(done) { | ||
events.emit(AUCTION_END, {}); | ||
|
||
const result = JSON.parse(requests[0].requestBody); | ||
expect(result).to.deep.equal(MOCK_DATA.expectedBidResponse); | ||
|
||
done(); | ||
}); | ||
}); | ||
}); |