Skip to content

Commit

Permalink
Add e-planning analytics adapter (#2211)
Browse files Browse the repository at this point in the history
* Add e-planning analytics adapter

* fix irregular spacing in braces

* Added new ci config option

* Fix linting
  • Loading branch information
matimar authored and idettman committed Mar 15, 2018
1 parent 2f6076e commit 717b439
Show file tree
Hide file tree
Showing 3 changed files with 316 additions and 0 deletions.
131 changes: 131 additions & 0 deletions modules/eplanningAnalyticsAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import {ajax} from 'src/ajax';
import adapter from 'src/AnalyticsAdapter';
import adaptermanager from 'src/adaptermanager';
import * as utils from 'src/utils';

const CONSTANTS = require('src/constants.json');

const analyticsType = 'endpoint';
const EPL_HOST = 'https://ads.us.e-planning.net/hba/1/';

function auctionEndHandler(args) {
return {auctionId: args.auctionId};
}

function auctionInitHandler(args) {
return {
auctionId: args.auctionId,
time: args.timestamp
};
}

function bidRequestedHandler(args) {
return {
auctionId: args.auctionId,
time: args.start,
bidder: args.bidderCode,
bids: args.bids.map(function(bid) {
return {
time: bid.startTime,
bidder: bid.bidder,
placementCode: bid.placementCode,
auctionId: bid.auctionId,
sizes: bid.sizes
};
}),
};
}

function bidResponseHandler(args) {
return {
bidder: args.bidder,
size: args.size,
auctionId: args.auctionId,
cpm: args.cpm,
time: args.responseTimestamp,
};
}

function bidWonHandler(args) {
return {
auctionId: args.auctionId,
size: args.width + 'x' + args.height,
};
}

function bidTimeoutHandler(args) {
return args.map(function(bid) {
return {
bidder: bid.bidder,
auctionId: bid.auctionId
};
})
}

function callHandler(evtype, args) {
let handler = null;

if (evtype === CONSTANTS.EVENTS.AUCTION_INIT) {
handler = auctionInitHandler;
eplAnalyticsAdapter.context.events = [];
} else if (evtype === CONSTANTS.EVENTS.AUCTION_END) {
handler = auctionEndHandler;
} else if (evtype === CONSTANTS.EVENTS.BID_REQUESTED) {
handler = bidRequestedHandler;
} else if (evtype === CONSTANTS.EVENTS.BID_RESPONSE) {
handler = bidResponseHandler
} else if (evtype === CONSTANTS.EVENTS.BID_TIMEOUT) {
handler = bidTimeoutHandler;
} else if (evtype === CONSTANTS.EVENTS.BID_WON) {
handler = bidWonHandler;
}

if (handler) {
eplAnalyticsAdapter.context.events.push({ec: evtype, p: handler(args)});
}
}

var eplAnalyticsAdapter = Object.assign(adapter(
{
EPL_HOST,
analyticsType
}),
{
track({eventType, args}) {
if (typeof args !== 'undefined') {
callHandler(eventType, args);
}

if (eventType === CONSTANTS.EVENTS.AUCTION_END) {
try {
let strjson = JSON.stringify(eplAnalyticsAdapter.context.events);
ajax(eplAnalyticsAdapter.context.host + eplAnalyticsAdapter.context.ci + '?d=' + encodeURIComponent(strjson));
} catch (err) {}
}
}
}
);

eplAnalyticsAdapter.originEnableAnalytics = eplAnalyticsAdapter.enableAnalytics;

eplAnalyticsAdapter.enableAnalytics = function (config) {
if (!config.options.ci) {
utils.logError('Client ID (ci) option is not defined. Analytics won\'t work');
return;
}

eplAnalyticsAdapter.context = {
events: [],
host: config.options.host || EPL_HOST,
ci: config.options.ci
};

eplAnalyticsAdapter.originEnableAnalytics(config);
};

adaptermanager.registerAnalyticsAdapter({
adapter: eplAnalyticsAdapter,
code: 'eplanning'
});

export default eplAnalyticsAdapter;
23 changes: 23 additions & 0 deletions modules/eplanningAnalyticsAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Overview

```
Module Name: E-Planning Analytics Adapter
Module Type: Analytics Adapter
Maintainer: mmartinho@e-planning.net
```

# Description

Analytics adapter for E-Planning.

# Test Parameters

```
{
provider: 'eplanning',
options : {
host: 'https://ads.us.e-planning.net/hba/1/', // Host (optional)
ci: "123456" // Client ID (required)
}
}
```
162 changes: 162 additions & 0 deletions test/spec/modules/eplanningAnalyticsAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import eplAnalyticsAdapter from 'modules/eplanningAnalyticsAdapter';
import { expect } from 'chai';
let adaptermanager = require('src/adaptermanager');
let events = require('src/events');
let constants = require('src/constants.json');

describe('eplanning analytics adapter', () => {
let xhr;
let requests;

beforeEach(() => {
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = request => { requests.push(request) };
sinon.stub(events, 'getEvents').returns([]);
});

afterEach(() => {
xhr.restore();
events.getEvents.restore();
});

describe('track', () => {
it('builds and sends auction data', () => {
sinon.spy(eplAnalyticsAdapter, 'track');

let auctionTimestamp = 1496510254313;
let pauctionId = '5018eb39-f900-4370-b71e-3bb5b48d324f';
let initOptions = {
host: 'https://ads.ar.e-planning.net/hba/1/',
ci: '12345'
};
let pbidderCode = 'adapter';

const bidRequest = {
bidderCode: pbidderCode,
auctionId: pauctionId,
bidderRequestId: '1a6fc81528d0f6',
bids: [{
bidder: pbidderCode,
placementCode: 'container-1',
bidId: '208750227436c1',
bidderRequestId: '1a6fc81528d0f6',
auctionId: pauctionId,
startTime: 1509369418389,
sizes: [[300, 250]],
}],
auctionStart: 1509369418387,
timeout: 3000,
start: 1509369418389
};

const bidResponse = {
bidderCode: pbidderCode,
adId: '208750227436c1',
cpm: 0.015,
auctionId: pauctionId,
responseTimestamp: 1509369418832,
requestTimestamp: 1509369418389,
bidder: pbidderCode,
timeToRespond: 443,
size: '300x250',
width: 300,
height: 250,
};

let bidTimeout = [
{
bidId: '208750227436c1',
bidder: pbidderCode,
auctionId: pauctionId
}
];

adaptermanager.registerAnalyticsAdapter({
code: 'eplanning',
adapter: eplAnalyticsAdapter
});

adaptermanager.enableAnalytics({
provider: 'eplanning',
options: initOptions
});

// Emit the events with the "real" arguments

// Step 1: Send auction init event
events.emit(constants.EVENTS.AUCTION_INIT, {
auctionId: pauctionId,
timestamp: auctionTimestamp
});

// Step 2: Send bid requested event
events.emit(constants.EVENTS.BID_REQUESTED, bidRequest);

// Step 3: Send bid response event
events.emit(constants.EVENTS.BID_RESPONSE, bidResponse);

// Step 4: Send bid time out event
events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout);

// Step 5: Send auction bid won event
events.emit(constants.EVENTS.BID_WON, {
adId: 'adIdData',
ad: 'adContent',
auctionId: pauctionId,
width: 300,
height: 250
});

// Step 6: Send auction end event
events.emit(constants.EVENTS.AUCTION_END, {auctionId: pauctionId});

// Step 7: Find the request data sent (filtering other hosts)
requests = requests.filter(req => req.url.includes(initOptions.host));

expect(requests.length).to.equal(1);

expect(requests[0].url.includes(initOptions.host + initOptions.ci));
expect(requests[0].url.includes('https://ads.ar.e-planning.net/hba/1/12345?d='));

let info = requests[0].url;
let purl = new URL(info);
let eplData = JSON.parse(decodeURIComponent(purl.searchParams.get('d')));

// Step 8 check that 6 events were sent
expect(eplData.length).to.equal(6);

// Step 9 verify that we only receive the parameters we need
let expectedEventValues = [
// AUCTION INIT
{ec: constants.EVENTS.AUCTION_INIT,
p: {auctionId: pauctionId, time: auctionTimestamp}},
// BID REQ
{ec: constants.EVENTS.BID_REQUESTED,
p: {auctionId: pauctionId, time: 1509369418389, bidder: pbidderCode, bids: [{time: 1509369418389, sizes: [[300, 250]], bidder: pbidderCode, placementCode: 'container-1', auctionId: pauctionId}]}},
// BID RESP
{ec: constants.EVENTS.BID_RESPONSE,
p: {auctionId: pauctionId, bidder: pbidderCode, cpm: 0.015, size: '300x250', time: 1509369418832}},
// BID T.O.
{ec: constants.EVENTS.BID_TIMEOUT,
p: [{auctionId: pauctionId, bidder: pbidderCode}]},
// BID WON
{ec: constants.EVENTS.BID_WON,
p: {auctionId: pauctionId, size: '300x250'}},
// AUCTION END
{ec: constants.EVENTS.AUCTION_END,
p: {auctionId: pauctionId}}
];

for (let evid = 0; evid < eplData.length; evid++) {
expect(eplData[evid]).to.deep.equal(expectedEventValues[evid]);
}

// Step 10 check that the host to send the ajax request is configurable via options
expect(eplAnalyticsAdapter.context.host).to.equal(initOptions.host);

// Step 11 verify that we received 6 events
sinon.assert.callCount(eplAnalyticsAdapter.track, 6);
});
});
});

0 comments on commit 717b439

Please sign in to comment.