Skip to content

Commit

Permalink
Adding Scaleable Analytics Adapter (prebid#3846)
Browse files Browse the repository at this point in the history
* Adding Scaleable Analytics Adapter

* Removed commented out code
  • Loading branch information
cconnors1515 authored and sa1omon committed Nov 28, 2019
1 parent 99ea60b commit 72caf98
Show file tree
Hide file tree
Showing 3 changed files with 309 additions and 0 deletions.
153 changes: 153 additions & 0 deletions modules/scaleableAnalyticsAdapter.js
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;
20 changes: 20 additions & 0 deletions modules/scaleableAnalyticsAdapter.md
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
}
});
```
136 changes: 136 additions & 0 deletions test/spec/modules/scaleableAnalyticsAdapter_spec.js
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();
});
});
});

0 comments on commit 72caf98

Please sign in to comment.