From 5e27370b550451cb07cd75304a9e7af157312c5f Mon Sep 17 00:00:00 2001
From: Dan Bogdan <43830380+EMXDigital@users.noreply.github.com>
Date: Wed, 24 Oct 2018 10:46:39 -0400
Subject: [PATCH 01/62] Submitting EMX Digital Adapter (#3173)
* Submitting EMX Digital Prebid Adapter
Submitting EMX Digital Prebid Adapter code
* fixing lint errors. updating our md
* updating to const/let variables. adding test spec.
* fixed linting on test spec js
---
modules/emx_digitalBidAdapter.js | 108 ++++++
modules/emx_digitalBidAdapter.md | 38 ++
.../modules/emx_digitalBidAdapter_spec.js | 338 ++++++++++++++++++
3 files changed, 484 insertions(+)
create mode 100644 modules/emx_digitalBidAdapter.js
create mode 100644 modules/emx_digitalBidAdapter.md
create mode 100644 test/spec/modules/emx_digitalBidAdapter_spec.js
diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js
new file mode 100644
index 00000000000..c25c20f2eda
--- /dev/null
+++ b/modules/emx_digitalBidAdapter.js
@@ -0,0 +1,108 @@
+import * as utils from 'src/utils';
+import {
+ registerBidder
+} from 'src/adapters/bidderFactory';
+import {
+ BANNER
+} from 'src/mediaTypes';
+import {
+ config
+} from 'src/config';
+
+const BIDDER_CODE = 'emx_digital';
+const ENDPOINT = 'hb.emxdgt.com';
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: [BANNER],
+ isBidRequestValid: function (bid) {
+ return !!(bid.params.tagid);
+ },
+ buildRequests: function (validBidRequests, bidRequests) {
+ const {host, href, protocol} = utils.getTopWindowLocation();
+ let emxData = {};
+ let emxImps = [];
+ const auctionId = bidRequests.auctionId;
+ const timeout = config.getConfig('bidderTimeout');
+ const timestamp = Date.now();
+ const url = location.protocol + '//' + ENDPOINT + ('?t=' + timeout + '&ts=' + timestamp);
+
+ utils._each(validBidRequests, function (bid) {
+ let tagId = String(utils.getBidIdParameter('tagid', bid.params));
+ let bidFloor = utils.getBidIdParameter('bidfloor', bid.params) || 0;
+ let emxBid = {
+ id: bid.bidId,
+ tid: bid.transactionId,
+ tagid: tagId,
+ secure: protocol === 'https:' ? 1 : 0,
+ banner: {
+ format: bid.sizes.map(function (size) {
+ return {
+ w: size[0],
+ h: size[1]
+ };
+ }),
+ w: bid.sizes[0][0],
+ h: bid.sizes[0][1]
+ }
+ }
+ if (bidFloor > 0) {
+ emxBid.bidfloor = bidFloor
+ }
+ emxImps.push(emxBid);
+ });
+ emxData = {
+ id: auctionId,
+ imp: emxImps,
+ site: {
+ domain: host,
+ page: href
+ }
+ };
+ if (bidRequests.gdprConsent) {
+ emxData.regs = {
+ ext: {
+ gdpr: bidRequests.gdprConsent.gdprApplies === true ? 1 : 0
+ }
+ };
+ }
+ if (bidRequests.gdprConsent && bidRequests.gdprConsent.gdprApplies) {
+ emxData.user = {
+ ext: {
+ consent: bidRequests.gdprConsent.consentString
+ }
+ };
+ }
+ return {
+ method: 'POST',
+ url: url,
+ data: JSON.stringify(emxData),
+ options: {
+ withCredentials: true
+ }
+ };
+ },
+ interpretResponse: function (serverResponse) {
+ let emxBidResponses = [];
+ let response = serverResponse.body || {};
+ if (response.seatbid && response.seatbid.length > 0 && response.seatbid[0].bid) {
+ response.seatbid.forEach(function (emxBid) {
+ emxBid = emxBid.bid[0];
+ emxBidResponses.push({
+ requestId: emxBid.id,
+ cpm: emxBid.price,
+ width: emxBid.w,
+ height: emxBid.h,
+ creativeId: emxBid.crid || emxBid.id,
+ dealId: emxBid.dealid || null,
+ currency: 'USD',
+ netRevenue: true,
+ mediaType: BANNER,
+ ad: decodeURIComponent(emxBid.adm),
+ ttl: emxBid.ttl
+ });
+ });
+ }
+ return emxBidResponses;
+ }
+};
+registerBidder(spec);
diff --git a/modules/emx_digitalBidAdapter.md b/modules/emx_digitalBidAdapter.md
new file mode 100644
index 00000000000..c9435e2f1d1
--- /dev/null
+++ b/modules/emx_digitalBidAdapter.md
@@ -0,0 +1,38 @@
+# Overview
+
+```
+Module Name: EMX Digital Adapter
+Module Type: Bidder Adapter
+Maintainer: git@emxdigital.com
+```
+
+# Description
+
+The EMX Digital adapter provides publishers with access to the EMX Marketplace. The adapter is GDPR compliant. Please note that the adapter supports Banner media type only.
+
+Note: The EMX Digital adapter requires approval and implementation guidelines from the EMX team, including existing publishers that work with EMX Digital. Please reach out to your account manager or prebid@emxdigital.com for more information.
+
+The bidder code should be ```emx_digital```
+The params used by the bidder are :
+```tagid``` - string (mandatory)
+```bidfloor``` - string (optional)
+
+# Test Parameters
+```
+var adUnits = [{
+ code: 'banner-div',
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250], [300, 600]
+ }
+ },
+ bids: [
+ {
+ bidder: 'emx_digital',
+ params: {
+ tagid: '25251',
+ }
+ }]
+}];
+```
diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js
new file mode 100644
index 00000000000..dd34582e22d
--- /dev/null
+++ b/test/spec/modules/emx_digitalBidAdapter_spec.js
@@ -0,0 +1,338 @@
+import { expect } from 'chai';
+import { spec } from 'modules/emx_digitalBidAdapter';
+import * as utils from 'src/utils';
+import { newBidder } from 'src/adapters/bidderFactory';
+
+describe('emx_digital Adapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('required function', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ let bid = {
+ 'bidder': 'emx_digital',
+ 'params': {
+ 'tagid': '25251'
+ },
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ],
+ 'bidId': '30b31c2501de1e',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'auctionId': '1d1a01234a475'
+ };
+
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should contain tagid param', function () {
+ expect(spec.isBidRequestValid({
+ params: {}
+ })).to.equal(false);
+ expect(spec.isBidRequestValid({
+ params: {
+ tagid: ''
+ }
+ })).to.equal(false);
+ expect(spec.isBidRequestValid({
+ params: {
+ tagid: '123'
+ }
+ })).to.equal(true);
+ });
+ });
+
+ describe('buildRequests', function () {
+ const bidRequests = [{
+ 'bidder': 'emx_digital',
+ 'params': {
+ 'tagid': '25251'
+ },
+ 'adUnitCode': 'adunit-code',
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ]
+ }
+ },
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ],
+ 'bidId': '30b31c2501de1e',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec'
+ }, {
+ 'bidder': 'emx_digital',
+ 'params': {
+ 'tagid': '25251'
+ },
+ 'adUnitCode': 'adunit-code',
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ]
+ }
+ },
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ],
+ 'bidId': '30b31c2501de1e',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec'
+ }];
+ let bidderRequest = {
+ 'bidderCode': 'emx_digital',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'timeout': 1500,
+ };
+ bidderRequest.bids = bidRequests
+
+ let request = spec.buildRequests(bidRequests, bidderRequest);
+
+ it('sends bid request to ENDPOINT via POST', function () {
+ expect(request.method).to.equal('POST');
+ });
+
+ it('contains the correct options', function () {
+ expect(request.options.withCredentials).to.equal(true);
+ });
+
+ it('sends contains a properly formatted endpoint url', function () {
+ const url = request.url.split('?');
+ const queryParams = url[1].split('&');
+ expect(queryParams[0]).to.match(new RegExp('^t=\d*', 'g'));
+ expect(queryParams[1]).to.match(new RegExp('^ts=\d*', 'g'));
+ });
+
+ it('builds request properly', function () {
+ const data = JSON.parse(request.data);
+
+ expect(Array.isArray(data.imp)).to.equal(true);
+ expect(data.id).to.equal(bidderRequest.auctionId);
+ expect(data.imp.length).to.equal(2);
+ expect(data.imp[0].id).to.equal('30b31c2501de1e');
+ expect(data.imp[0].tid).to.equal('d7b773de-ceaa-484d-89ca-d9f51b8d61ec');
+ expect(data.imp[0].tagid).to.equal('25251');
+ expect(data.imp[0].secure).to.equal(0);
+ });
+
+ it('builds with bid floor', function() {
+ const bidRequestWithBidFloor = utils.deepClone(bidRequests);
+ bidRequestWithBidFloor[0].params.bidfloor = 1;
+ const requestWithFloor = spec.buildRequests(bidRequestWithBidFloor, bidderRequest);
+ const data = JSON.parse(requestWithFloor.data);
+ expect(data.imp[0].bidfloor).to.equal(bidRequestWithBidFloor[0].params.bidfloor);
+ })
+
+ it('properly sends site information and protocol', function () {
+ let mock = sinon.stub(utils, 'getTopWindowLocation').callsFake(() => {
+ return {
+ protocol: 'https:',
+ host: 'example.com',
+ href: 'https://example.com/index.html'
+ };
+ });
+
+ let request;
+
+ request = spec.buildRequests(bidRequests, bidderRequest);
+ request = JSON.parse(request.data);
+ expect(request.site.domain).to.equal('example.com');
+ expect(request.site.page).to.equal('https://example.com/index.html');
+ expect(request.imp[0].secure).to.equal(1);
+
+ mock.restore();
+ })
+
+ it('builds correctly formatted request banner object', function () {
+ let request;
+
+ let bidRequestWithBanner = utils.deepClone(bidRequests);
+
+ request = spec.buildRequests(bidRequestWithBanner, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.imp[0].banner.w).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][0]);
+ expect(data.imp[0].banner.h).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][1]);
+ expect(data.imp[0].banner.format[0].w).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][0]);
+ expect(data.imp[0].banner.format[0].h).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][1]);
+ expect(data.imp[0].banner.format[1].w).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[1][0]);
+ expect(data.imp[0].banner.format[1].h).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[1][1]);
+ })
+
+ it('shouldn\'t contain a user obj without GDPR information', function () {
+ let request = spec.buildRequests(bidRequests, bidderRequest)
+ request = JSON.parse(request.data)
+ expect(request).to.not.have.property('user');
+ });
+
+ it('should have the right gdpr info when enabled', function () {
+ let consentString = 'OIJSZsOAFsABAB8EMXZZZZZ+A==';
+ let bidderRequest = {
+ 'bidderCode': 'emx_digital',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'timeout': 1500,
+ 'gdprConsent': {
+ 'consentString': consentString,
+ 'gdprApplies': true
+ }
+ };
+ bidderRequest.bids = bidRequests
+ let request = spec.buildRequests(bidRequests, bidderRequest);
+
+ request = JSON.parse(request.data)
+ expect(request.regs.ext).to.have.property('gdpr', 1);
+ expect(request.user.ext).to.have.property('consent', 'OIJSZsOAFsABAB8EMXZZZZZ+A==');
+ });
+
+ it('should\'t contain consent string if gdpr isn\'t applied', function () {
+ let bidderRequest = {
+ 'bidderCode': 'emx_digital',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'timeout': 1500,
+ 'gdprConsent': {
+ 'gdprApplies': false
+ }
+ };
+ bidderRequest.bids = bidRequests
+ let request = spec.buildRequests(bidRequests, bidderRequest);
+
+ request = JSON.parse(request.data)
+ expect(request.regs.ext).to.have.property('gdpr', 0);
+ expect(request).to.not.have.property('user');
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const serverResponse = {
+ 'id': '12819a18-56e1-4256-b836-b69a10202668',
+ 'seatbid': [{
+ 'bid': [{
+ 'adid': '123456abcde',
+ 'adm': '',
+ 'crid': '3434abab34',
+ 'h': 250,
+ 'id': '987654321cba',
+ 'price': 0.5,
+ 'ttl': 300,
+ 'w': 300
+ }],
+ 'seat': '1356'
+ }, {
+ 'bid': [{
+ 'adid': '123456abcdf',
+ 'adm': '',
+ 'crid': '3434abab35',
+ 'h': 600,
+ 'id': '987654321cba',
+ 'price': 0.5,
+ 'ttl': 300,
+ 'w': 300
+ }]
+ }]
+ };
+
+ const expectedResponse = [{
+ 'requestId': '12819a18-56e1-4256-b836-b69a10202668',
+ 'cpm': 0.5,
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': '3434abab34',
+ 'dealId': null,
+ 'currency': 'USD',
+ 'netRevneue': true,
+ 'mediaType': 'banner',
+ 'ad': '',
+ 'ttl': 300
+ }, {
+ 'requestId': '12819a18-56e1-4256-b836-b69a10202668',
+ 'cpm': 0.7,
+ 'width': 300,
+ 'height': 600,
+ 'creativeId': '3434abab35',
+ 'dealId': null,
+ 'currency': 'USD',
+ 'netRevneue': true,
+ 'mediaType': 'banner',
+ 'ad': '',
+ 'ttl': 300
+ }];
+
+ it('should properly format bid response', function () {
+ let result = spec.interpretResponse({
+ body: serverResponse
+ });
+ expect(Object.keys(result[0]).length).to.equal(Object.keys(expectedResponse[0]).length);
+ expect(Object.keys(result[0]).requestId).to.equal(Object.keys(expectedResponse[0]).requestId);
+ expect(Object.keys(result[0]).bidderCode).to.equal(Object.keys(expectedResponse[0]).bidderCode);
+ expect(Object.keys(result[0]).cpm).to.equal(Object.keys(expectedResponse[0]).cpm);
+ expect(Object.keys(result[0]).creativeId).to.equal(Object.keys(expectedResponse[0]).creativeId);
+ expect(Object.keys(result[0]).width).to.equal(Object.keys(expectedResponse[0]).width);
+ expect(Object.keys(result[0]).height).to.equal(Object.keys(expectedResponse[0]).height);
+ expect(Object.keys(result[0]).ttl).to.equal(Object.keys(expectedResponse[0]).ttl);
+ expect(Object.keys(result[0]).adId).to.equal(Object.keys(expectedResponse[0]).adId);
+ expect(Object.keys(result[0]).currency).to.equal(Object.keys(expectedResponse[0]).currency);
+ expect(Object.keys(result[0]).netRevenue).to.equal(Object.keys(expectedResponse[0]).netRevenue);
+ expect(Object.keys(result[0]).ad).to.equal(Object.keys(expectedResponse[0]).ad);
+ });
+
+ it('should return multiple bids', function () {
+ let result = spec.interpretResponse({
+ body: serverResponse
+ });
+ expect(Array.isArray(result.seatbid))
+
+ const ad0 = result[0];
+ const ad1 = result[1];
+ expect(ad0.ad).to.equal(serverResponse.seatbid[0].bid[0].adm);
+ expect(ad0.cpm).to.equal(serverResponse.seatbid[0].bid[0].price);
+ expect(ad0.creativeId).to.equal(serverResponse.seatbid[0].bid[0].crid);
+ expect(ad0.currency).to.equal('USD');
+ expect(ad0.height).to.equal(serverResponse.seatbid[0].bid[0].h);
+ expect(ad0.mediaType).to.equal('banner');
+ expect(ad0.netRevenue).to.equal(true);
+ expect(ad0.requestId).to.equal(serverResponse.seatbid[0].bid[0].id);
+ expect(ad0.ttl).to.equal(300);
+ expect(ad0.width).to.equal(serverResponse.seatbid[0].bid[0].w);
+
+ expect(ad1.ad).to.equal(serverResponse.seatbid[1].bid[0].adm);
+ expect(ad1.cpm).to.equal(serverResponse.seatbid[1].bid[0].price);
+ expect(ad1.creativeId).to.equal(serverResponse.seatbid[1].bid[0].crid);
+ expect(ad1.currency).to.equal('USD');
+ expect(ad1.height).to.equal(serverResponse.seatbid[1].bid[0].h);
+ expect(ad1.mediaType).to.equal('banner');
+ expect(ad1.netRevenue).to.equal(true);
+ expect(ad1.requestId).to.equal(serverResponse.seatbid[1].bid[0].id);
+ expect(ad1.ttl).to.equal(300);
+ expect(ad1.width).to.equal(serverResponse.seatbid[1].bid[0].w);
+ });
+
+ it('handles nobid responses', function () {
+ let serverResponse = {
+ 'bids': []
+ };
+
+ let result = spec.interpretResponse({
+ body: serverResponse
+ });
+ expect(result.length).to.equal(0);
+ });
+ });
+});
From 2863df1090a79d570fdddd12974a7da62fa98b3b Mon Sep 17 00:00:00 2001
From: TheMediaGrid <44166371+TheMediaGrid@users.noreply.github.com>
Date: Thu, 25 Oct 2018 23:03:19 +0300
Subject: [PATCH 02/62] TheMediaGrid Bid Adapter (#3204)
* Added Grid Bid Adapter
* remove priceType from TheMediaGrid Bid Adapter
---
modules/gridBidAdapter.js | 151 ++++++++++++
modules/gridBidAdapter.md | 40 +++
test/spec/modules/gridBidAdapter_spec.js | 299 +++++++++++++++++++++++
3 files changed, 490 insertions(+)
create mode 100644 modules/gridBidAdapter.js
create mode 100755 modules/gridBidAdapter.md
create mode 100644 test/spec/modules/gridBidAdapter_spec.js
diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js
new file mode 100644
index 00000000000..660b5c66a78
--- /dev/null
+++ b/modules/gridBidAdapter.js
@@ -0,0 +1,151 @@
+import * as utils from 'src/utils';
+import {registerBidder} from 'src/adapters/bidderFactory';
+const BIDDER_CODE = 'grid';
+const ENDPOINT_URL = '//grid.bidswitch.net/hb';
+const TIME_TO_LIVE = 360;
+const LOG_ERROR_MESS = {
+ noAuid: 'Bid from response has no auid parameter - ',
+ noAdm: 'Bid from response has no adm parameter - ',
+ noBid: 'Array of bid objects is empty',
+ noPlacementCode: 'Can\'t find in requested bids the bid with auid - ',
+ emptyUids: 'Uids should be not empty',
+ emptySeatbid: 'Seatbid array from response has empty item',
+ emptyResponse: 'Response is empty',
+ hasEmptySeatbidArray: 'Response has empty seatbid array',
+ hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - '
+};
+export const spec = {
+ code: BIDDER_CODE,
+ /**
+ * Determines whether or not the given bid request is valid.
+ *
+ * @param {BidRequest} bid The bid params to validate.
+ * @return boolean True if this is a valid bid, and false otherwise.
+ */
+ isBidRequestValid: function(bid) {
+ return !!bid.params.uid;
+ },
+ /**
+ * Make a server request from the list of BidRequests.
+ *
+ * @param {BidRequest[]} validBidRequests - an array of bids
+ * @param {bidderRequest} bidderRequest bidder request object
+ * @return ServerRequest Info describing the request to the server.
+ */
+ buildRequests: function(validBidRequests, bidderRequest) {
+ const auids = [];
+ const bidsMap = {};
+ const bids = validBidRequests || [];
+ let reqId;
+
+ bids.forEach(bid => {
+ reqId = bid.bidderRequestId;
+ if (!bidsMap[bid.params.uid]) {
+ bidsMap[bid.params.uid] = [bid];
+ auids.push(bid.params.uid);
+ } else {
+ bidsMap[bid.params.uid].push(bid);
+ }
+ });
+
+ const payload = {
+ u: utils.getTopWindowUrl(),
+ auids: auids.join(','),
+ r: reqId
+ };
+
+ if (bidderRequest) {
+ if (bidderRequest.timeout) {
+ payload.wtimeout = bidderRequest.timeout;
+ }
+ if (bidderRequest.gdprConsent) {
+ if (bidderRequest.gdprConsent.consentString) {
+ payload.gdpr_consent = bidderRequest.gdprConsent.consentString;
+ }
+ payload.gdpr_applies =
+ (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean')
+ ? Number(bidderRequest.gdprConsent.gdprApplies) : 1;
+ }
+ }
+
+ return {
+ method: 'GET',
+ url: ENDPOINT_URL,
+ data: utils.parseQueryStringParameters(payload).replace(/\&$/, ''),
+ bidsMap: bidsMap,
+ };
+ },
+ /**
+ * Unpack the response from the server into a list of bids.
+ *
+ * @param {*} serverResponse A successful response from the server.
+ * @param {*} bidRequest
+ * @return {Bid[]} An array of bids which were nested inside the server.
+ */
+ interpretResponse: function(serverResponse, bidRequest) {
+ serverResponse = serverResponse && serverResponse.body;
+ const bidResponses = [];
+ const bidsMap = bidRequest.bidsMap;
+
+ let errorMessage;
+
+ if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse;
+ else if (serverResponse.seatbid && !serverResponse.seatbid.length) {
+ errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray;
+ }
+
+ if (!errorMessage && serverResponse.seatbid) {
+ serverResponse.seatbid.forEach(respItem => {
+ _addBidResponse(_getBidFromResponse(respItem), bidsMap, bidResponses);
+ });
+ }
+ if (errorMessage) utils.logError(errorMessage);
+ return bidResponses;
+ }
+}
+
+function _getBidFromResponse(respItem) {
+ if (!respItem) {
+ utils.logError(LOG_ERROR_MESS.emptySeatbid);
+ } else if (!respItem.bid) {
+ utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem));
+ } else if (!respItem.bid[0]) {
+ utils.logError(LOG_ERROR_MESS.noBid);
+ }
+ return respItem && respItem.bid && respItem.bid[0];
+}
+
+function _addBidResponse(serverBid, bidsMap, bidResponses) {
+ if (!serverBid) return;
+ let errorMessage;
+ if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid);
+ if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid);
+ else {
+ const awaitingBids = bidsMap[serverBid.auid];
+ if (awaitingBids) {
+ awaitingBids.forEach(bid => {
+ const bidResponse = {
+ requestId: bid.bidId, // bid.bidderRequestId,
+ bidderCode: spec.code,
+ cpm: serverBid.price,
+ width: serverBid.w,
+ height: serverBid.h,
+ creativeId: serverBid.auid, // bid.bidId,
+ currency: 'USD',
+ netRevenue: false,
+ ttl: TIME_TO_LIVE,
+ ad: serverBid.adm,
+ dealId: serverBid.dealid
+ };
+ bidResponses.push(bidResponse);
+ });
+ } else {
+ errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid;
+ }
+ }
+ if (errorMessage) {
+ utils.logError(errorMessage);
+ }
+}
+
+registerBidder(spec);
diff --git a/modules/gridBidAdapter.md b/modules/gridBidAdapter.md
new file mode 100755
index 00000000000..9b7b0e0515e
--- /dev/null
+++ b/modules/gridBidAdapter.md
@@ -0,0 +1,40 @@
+# Overview
+
+Module Name: The Grid Media Bidder Adapter
+Module Type: Bidder Adapter
+Maintainer: grid-tech@themediagrid.com
+
+# Description
+
+Module that connects to Grid demand source to fetch bids.
+
+# Test Parameters
+```
+ var adUnits = [
+ {
+ code: 'test-div',
+ sizes: [[300, 250]],
+ bids: [
+ {
+ bidder: "grid",
+ params: {
+ uid: '1',
+ priceType: 'gross' // by default is 'net'
+ }
+ }
+ ]
+ },{
+ code: 'test-div',
+ sizes: [[728, 90]],
+ bids: [
+ {
+ bidder: "grid",
+ params: {
+ uid: 2,
+ priceType: 'gross'
+ }
+ }
+ ]
+ }
+ ];
+```
\ No newline at end of file
diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js
new file mode 100644
index 00000000000..f4401dfe677
--- /dev/null
+++ b/test/spec/modules/gridBidAdapter_spec.js
@@ -0,0 +1,299 @@
+import { expect } from 'chai';
+import { spec } from 'modules/gridBidAdapter';
+import { newBidder } from 'src/adapters/bidderFactory';
+
+describe('TheMediaGrid Adapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ let bid = {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '30b31c1838de1e',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475',
+ };
+
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should return false when required params are not passed', function () {
+ let bid = Object.assign({}, bid);
+ delete bid.params;
+ bid.params = {
+ 'uid': 0
+ };
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ function parseRequest(url) {
+ const res = {};
+ url.split('&').forEach((it) => {
+ const couple = it.split('=');
+ res[couple[0]] = decodeURIComponent(couple[1]);
+ });
+ return res;
+ }
+ let bidRequests = [
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '30b31c1838de1e',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-2',
+ 'sizes': [[728, 90]],
+ 'bidId': '3150ccb55da321',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '2'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '42dbe3a7168a6a',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475',
+ }
+ ];
+
+ it('should attach valid params to the tag', function () {
+ const request = spec.buildRequests([bidRequests[0]]);
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('u').that.is.a('string');
+ expect(payload).to.have.property('auids', '1');
+ expect(payload).to.have.property('r', '22edbae2733bf6');
+ });
+
+ it('auids must not be duplicated', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('u').that.is.a('string');
+ expect(payload).to.have.property('auids', '1,2');
+ expect(payload).to.have.property('r', '22edbae2733bf6');
+ });
+
+ it('if gdprConsent is present payload must have gdpr params', function () {
+ const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: true}});
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('gdpr_consent', 'AAA');
+ expect(payload).to.have.property('gdpr_applies', '1');
+ });
+
+ it('if gdprApplies is false gdpr_applies must be 0', function () {
+ const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: false}});
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('gdpr_consent', 'AAA');
+ expect(payload).to.have.property('gdpr_applies', '0');
+ });
+
+ it('if gdprApplies is undefined gdpr_applies must be 1', function () {
+ const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA'}});
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('gdpr_consent', 'AAA');
+ expect(payload).to.have.property('gdpr_applies', '1');
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const responses = [
+ {'bid': [{'price': 1.15, 'adm': '
test content 1
', 'auid': 1, 'h': 250, 'w': 300}], 'seat': '1'},
+ {'bid': [{'price': 0.5, 'adm': 'test content 2
', 'auid': 2, 'h': 90, 'w': 728}], 'seat': '1'},
+ {'bid': [{'price': 0, 'auid': 3, 'h': 250, 'w': 300}], 'seat': '1'},
+ {'bid': [{'price': 0, 'adm': 'test content 4
', 'h': 250, 'w': 300}], 'seat': '1'},
+ undefined,
+ {'bid': [], 'seat': '1'},
+ {'seat': '1'},
+ ];
+
+ it('should get correct bid response', function () {
+ const bidRequests = [
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '659423fff799cb',
+ 'bidderRequestId': '5f2009617a7c0a',
+ 'auctionId': '1cbd2feafe5e8b',
+ }
+ ];
+ const request = spec.buildRequests(bidRequests);
+ const expectedResponse = [
+ {
+ 'requestId': '659423fff799cb',
+ 'cpm': 1.15,
+ 'creativeId': 1,
+ 'dealId': undefined,
+ 'width': 300,
+ 'height': 250,
+ 'ad': 'test content 1
',
+ 'bidderCode': 'grid',
+ 'currency': 'USD',
+ 'netRevenue': false,
+ 'ttl': 360,
+ }
+ ];
+
+ const result = spec.interpretResponse({'body': {'seatbid': [responses[0]]}}, request);
+ expect(result).to.deep.equal(expectedResponse);
+ });
+
+ it('should get correct multi bid response', function () {
+ const bidRequests = [
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '300bfeb0d71a5b',
+ 'bidderRequestId': '2c2bb1972df9a',
+ 'auctionId': '1fa09aee5c8c99',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '2'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '4dff80cc4ee346',
+ 'bidderRequestId': '2c2bb1972df9a',
+ 'auctionId': '1fa09aee5c8c99',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-2',
+ 'sizes': [[728, 90]],
+ 'bidId': '5703af74d0472a',
+ 'bidderRequestId': '2c2bb1972df9a',
+ 'auctionId': '1fa09aee5c8c99',
+ }
+ ];
+ const request = spec.buildRequests(bidRequests);
+ const expectedResponse = [
+ {
+ 'requestId': '300bfeb0d71a5b',
+ 'cpm': 1.15,
+ 'creativeId': 1,
+ 'dealId': undefined,
+ 'width': 300,
+ 'height': 250,
+ 'ad': 'test content 1
',
+ 'bidderCode': 'grid',
+ 'currency': 'USD',
+ 'netRevenue': false,
+ 'ttl': 360,
+ },
+ {
+ 'requestId': '5703af74d0472a',
+ 'cpm': 1.15,
+ 'creativeId': 1,
+ 'dealId': undefined,
+ 'width': 300,
+ 'height': 250,
+ 'ad': 'test content 1
',
+ 'bidderCode': 'grid',
+ 'currency': 'USD',
+ 'netRevenue': false,
+ 'ttl': 360,
+ },
+ {
+ 'requestId': '4dff80cc4ee346',
+ 'cpm': 0.5,
+ 'creativeId': 2,
+ 'dealId': undefined,
+ 'width': 728,
+ 'height': 90,
+ 'ad': 'test content 2
',
+ 'bidderCode': 'grid',
+ 'currency': 'USD',
+ 'netRevenue': false,
+ 'ttl': 360,
+ }
+ ];
+
+ const result = spec.interpretResponse({'body': {'seatbid': [responses[0], responses[1]]}}, request);
+ expect(result).to.deep.equal(expectedResponse);
+ });
+
+ it('handles wrong and nobid responses', function () {
+ const bidRequests = [
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '3'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '300bfeb0d7190gf',
+ 'bidderRequestId': '2c2bb1972d23af',
+ 'auctionId': '1fa09aee5c84d34',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '4'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '300bfeb0d71321',
+ 'bidderRequestId': '2c2bb1972d23af',
+ 'auctionId': '1fa09aee5c84d34',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '5'
+ },
+ 'adUnitCode': 'adunit-code-2',
+ 'sizes': [[728, 90]],
+ 'bidId': '300bfeb0d7183bb',
+ 'bidderRequestId': '2c2bb1972d23af',
+ 'auctionId': '1fa09aee5c84d34',
+ }
+ ];
+ const request = spec.buildRequests(bidRequests);
+ const result = spec.interpretResponse({'body': {'seatbid': responses.slice(2)}}, request);
+ expect(result.length).to.equal(0);
+ });
+ });
+});
From 50a7cffcdcfdecd45d7c9ec02395df9313e189aa Mon Sep 17 00:00:00 2001
From: Dan Bogdan <43830380+EMXDigital@users.noreply.github.com>
Date: Thu, 25 Oct 2018 16:24:32 -0400
Subject: [PATCH 03/62] Adding user sync method for IFRAME and Pixel (#3232)
* Submitting EMX Digital Prebid Adapter
Submitting EMX Digital Prebid Adapter code
* fixing lint errors. updating our md
* updating to const/let variables. adding test spec.
* fixed linting on test spec js
* adding emx usersync methods
---
modules/emx_digitalBidAdapter.js | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js
index c25c20f2eda..042251ea035 100644
--- a/modules/emx_digitalBidAdapter.js
+++ b/modules/emx_digitalBidAdapter.js
@@ -103,6 +103,22 @@ export const spec = {
});
}
return emxBidResponses;
+ },
+ getUserSyncs: function (syncOptions) {
+ const syncs = [];
+ if (syncOptions.iframeEnabled) {
+ syncs.push({
+ type: 'iframe',
+ url: '//biddr.brealtime.com/check.html'
+ });
+ }
+ if (syncOptions.pixelEnabled) {
+ syncs.push({
+ type: 'image',
+ url: '//edba.brealtime.com/'
+ });
+ }
+ return syncs;
}
};
registerBidder(spec);
From 5743e2bf2e086fec09f87f6337319d507e81efc5 Mon Sep 17 00:00:00 2001
From: Stephen Johnston
Date: Fri, 26 Oct 2018 09:04:44 -0400
Subject: [PATCH 04/62] updates (#3162)
---
src/utils.js | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/src/utils.js b/src/utils.js
index 77dfe10c918..93b19485dfe 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -66,10 +66,22 @@ exports.getUniqueIdentifierStr = _getUniqueIdentifierStr;
*/
exports.generateUUID = function generateUUID(placeholder) {
return placeholder
- ? (placeholder ^ Math.random() * 16 >> placeholder / 4).toString(16)
+ ? (placeholder ^ _getRandomData() >> placeholder / 4).toString(16)
: ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, generateUUID);
};
+/**
+ * Returns random data using the Crypto API if available and Math.random if not
+ * Method is from https://gist.github.com/jed/982883 like generateUUID, direct link https://gist.github.com/jed/982883#gistcomment-45104
+ */
+function _getRandomData() {
+ if (window && window.crypto && window.crypto.getRandomValues) {
+ return crypto.getRandomValues(new Uint8Array(1))[0] % 16;
+ } else {
+ return Math.random() * 16;
+ }
+}
+
exports.getBidIdParameter = function (key, paramsObj) {
if (paramsObj && paramsObj[key]) {
return paramsObj[key];
From 6363197be50c1cad6a5c4a17ba71d85582d45e0d Mon Sep 17 00:00:00 2001
From: Kenan Shifflett
Date: Fri, 26 Oct 2018 11:15:06 -0400
Subject: [PATCH 05/62] Only set native targeting if value exists. (#3225)
---
src/native.js | 4 ++--
test/spec/native_spec.js | 23 +++++++++++++++++++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/src/native.js b/src/native.js
index b4d2d959b70..c9d274ddccd 100644
--- a/src/native.js
+++ b/src/native.js
@@ -147,7 +147,7 @@ export function fireNativeTrackers(message, adObject) {
}
/**
- * Gets native targeting key-value paris
+ * Gets native targeting key-value pairs
* @param {Object} bid
* @return {Object} targeting
*/
@@ -163,7 +163,7 @@ export function getNativeTargeting(bid) {
value = value.url;
}
- if (key) {
+ if (key && value) {
keyValues[key] = value;
}
});
diff --git a/test/spec/native_spec.js b/test/spec/native_spec.js
index 91b96cac281..68653808c06 100644
--- a/test/spec/native_spec.js
+++ b/test/spec/native_spec.js
@@ -16,6 +16,19 @@ const bid = {
}
};
+const bidWithUndefinedFields = {
+ native: {
+ title: 'Native Creative',
+ body: undefined,
+ cta: undefined,
+ sponsoredBy: 'AppNexus',
+ clickUrl: 'https://www.link.example',
+ clickTrackers: ['https://tracker.example'],
+ impressionTrackers: ['https://impression.example'],
+ javascriptTrackers: ''
+ }
+};
+
describe('native.js', function () {
let triggerPixelStub;
let insertHtmlIntoIframeStub;
@@ -37,6 +50,16 @@ describe('native.js', function () {
expect(targeting[CONSTANTS.NATIVE_KEYS.clickUrl]).to.equal(bid.native.clickUrl);
});
+ it('should only include native targeting keys with values', function () {
+ const targeting = getNativeTargeting(bidWithUndefinedFields);
+
+ expect(Object.keys(targeting)).to.deep.equal([
+ CONSTANTS.NATIVE_KEYS.title,
+ CONSTANTS.NATIVE_KEYS.sponsoredBy,
+ CONSTANTS.NATIVE_KEYS.clickUrl
+ ]);
+ });
+
it('fires impression trackers', function () {
fireNativeTrackers({}, bid);
sinon.assert.calledOnce(triggerPixelStub);
From e1f55ceb2f9385a080c80fb7d751d286b99356a6 Mon Sep 17 00:00:00 2001
From: Rich Snapp
Date: Fri, 26 Oct 2018 11:36:37 -0600
Subject: [PATCH 06/62] add nolint command line option, similar to notest
(#3234)
---
gulpfile.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/gulpfile.js b/gulpfile.js
index ced29b266a7..03a0a4a7559 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -76,7 +76,10 @@ function escapePostbidConfig() {
};
escapePostbidConfig.displayName = 'escape-postbid-config';
-function lint() {
+function lint(done) {
+ if (argv.nolint) {
+ return done();
+ }
return gulp.src(['src/**/*.js', 'modules/**/*.js', 'test/**/*.js'])
.pipe(eslint())
.pipe(eslint.format('stylish'))
From fda63ec22a96907333651f37be5ee08b370b8023 Mon Sep 17 00:00:00 2001
From: Micha Niskin
Date: Fri, 26 Oct 2018 15:50:56 -0400
Subject: [PATCH 07/62] add inskin iab vendor id: enables consent via string
(#3235)
---
modules/inskinBidAdapter.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/modules/inskinBidAdapter.js b/modules/inskinBidAdapter.js
index 0e7e28b9b6b..27d01e677ef 100644
--- a/modules/inskinBidAdapter.js
+++ b/modules/inskinBidAdapter.js
@@ -59,6 +59,7 @@ export const spec = {
if (bidderRequest && bidderRequest.gdprConsent) {
data.consent = {
+ gdprVendorId: 150,
gdprConsentString: bidderRequest.gdprConsent.consentString,
// will check if the gdprApplies field was populated with a boolean value (ie from page config). If it's undefined, then default to true
gdprConsentRequired: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true
From 67b24c9edff4a5845cafd7a03342deb397493c82 Mon Sep 17 00:00:00 2001
From: Omer Koren
Date: Mon, 29 Oct 2018 20:15:23 +0200
Subject: [PATCH 08/62] Added user sync support for undertone bid adapter
(#3172)
* Added user sync support for undertone bid adapter (new pull request)
* Added user sync support for undertone bid adapter
* fix indentation
* Changed utils.getWindowTop() with the newer prebid utilities
---
modules/undertoneBidAdapter.js | 77 +++++++++++++++----
test/spec/modules/undertoneBidAdapter_spec.js | 37 ++++++++-
2 files changed, 97 insertions(+), 17 deletions(-)
diff --git a/modules/undertoneBidAdapter.js b/modules/undertoneBidAdapter.js
index dd99df1fc7e..6d4ced88ba1 100644
--- a/modules/undertoneBidAdapter.js
+++ b/modules/undertoneBidAdapter.js
@@ -2,11 +2,44 @@
* Adapter to send bids to Undertone
*/
-import * as utils from 'src/utils';
+import * as urlUtils from 'src/url';
import { registerBidder } from 'src/adapters/bidderFactory';
const BIDDER_CODE = 'undertone';
const URL = '//hb.undertone.com/hb';
+const FRAME_USER_SYNC = '//cdn.undertone.com/js/usersync.html';
+const PIXEL_USER_SYNC_1 = '//usr.undertone.com/userPixel/syncOne?id=1&of=2';
+const PIXEL_USER_SYNC_2 = '//usr.undertone.com/userPixel/syncOne?id=2&of=2';
+
+function getCanonicalUrl() {
+ try {
+ let doc = window.top.document;
+ let element = doc.querySelector("link[rel='canonical']");
+ if (element !== null) {
+ return element.href;
+ }
+ } catch (e) {
+ }
+ return null;
+}
+
+function extractDomainFromHost(pageHost) {
+ let domain = null;
+ try {
+ let domains = /[-\w]+\.([-\w]+|[-\w]{3,}|[-\w]{1,3}\.[-\w]{2})$/i.exec(pageHost);
+ if (domains != null && domains.length > 0) {
+ domain = domains[0];
+ for (let i = 1; i < domains.length; i++) {
+ if (domains[i].length > domain.length) {
+ domain = domains[i];
+ }
+ }
+ }
+ } catch (e) {
+ domain = null;
+ }
+ return domain;
+}
export const spec = {
code: BIDDER_CODE,
@@ -16,21 +49,14 @@ export const spec = {
return true;
}
},
- buildRequests: function(validBidRequests) {
+ buildRequests: function(validBidRequests, bidderRequest) {
const payload = {
'x-ut-hb-params': []
};
- const location = utils.getTopWindowLocation();
- let domains = /[-\w]+\.([-\w]+|[-\w]{3,}|[-\w]{1,3}\.[-\w]{2})$/i.exec(location.host);
- let domain = null;
- if (domains != null && domains.length > 0) {
- domain = domains[0];
- for (let i = 1; i < domains.length; i++) {
- if (domains[i].length > domain.length) {
- domain = domains[i];
- }
- }
- }
+ const referer = bidderRequest.refererInfo.referer;
+ const hostname = urlUtils.parse(referer).hostname;
+ let domain = extractDomainFromHost(hostname);
+ const pageUrl = getCanonicalUrl() || referer;
const pubid = validBidRequests[0].params.publisherId;
const REQ_URL = `${URL}?pid=${pubid}&domain=${domain}`;
@@ -39,7 +65,7 @@ export const spec = {
const bid = {
bidRequestId: bidReq.bidId,
hbadaptor: 'prebid',
- url: location.href,
+ url: pageUrl,
domain: domain,
placementId: bidReq.params.placementId != undefined ? bidReq.params.placementId : null,
publisherId: bidReq.params.publisherId,
@@ -78,6 +104,29 @@ export const spec = {
});
}
return bids;
+ },
+ getUserSyncs: function(syncOptions, serverResponses, gdprConsent) {
+ const syncs = [];
+ if (gdprConsent && gdprConsent.gdprApplies === true) {
+ return syncs;
+ }
+
+ if (syncOptions.iframeEnabled) {
+ syncs.push({
+ type: 'iframe',
+ url: FRAME_USER_SYNC
+ });
+ } else if (syncOptions.pixelEnabled) {
+ syncs.push({
+ type: 'image',
+ url: PIXEL_USER_SYNC_1
+ },
+ {
+ type: 'image',
+ url: PIXEL_USER_SYNC_2
+ });
+ }
+ return syncs;
}
};
registerBidder(spec);
diff --git a/test/spec/modules/undertoneBidAdapter_spec.js b/test/spec/modules/undertoneBidAdapter_spec.js
index 4b816d851d9..400e86567ea 100644
--- a/test/spec/modules/undertoneBidAdapter_spec.js
+++ b/test/spec/modules/undertoneBidAdapter_spec.js
@@ -44,6 +44,12 @@ const bidReq = [{
auctionId: '6c22f5a5-59df-4dc6-b92c-f433bcf0a874'
}];
+const bidderReq = {
+ refererInfo: {
+ referer: 'http://prebid.org/dev-docs/bidder-adaptor.html'
+ }
+};
+
const validBidRes = {
ad: 'Hello
',
publisherId: 12345,
@@ -98,14 +104,16 @@ describe('Undertone Adapter', function () {
});
describe('build request', function () {
it('should send request to correct url via POST', function () {
- const request = spec.buildRequests(bidReq);
- const domain = null;
+ const request = spec.buildRequests(bidReq, bidderReq);
+ const domainStart = bidderReq.refererInfo.referer.indexOf('//');
+ const domainEnd = bidderReq.refererInfo.referer.indexOf('/', domainStart + 2);
+ const domain = bidderReq.refererInfo.referer.substring(domainStart + 2, domainEnd);
const REQ_URL = `${URL}?pid=${bidReq[0].params.publisherId}&domain=${domain}`;
expect(request.url).to.equal(REQ_URL);
expect(request.method).to.equal('POST');
});
it('should have all relevant fields', function () {
- const request = spec.buildRequests(bidReq);
+ const request = spec.buildRequests(bidReq, bidderReq);
const bid1 = JSON.parse(request.data)['x-ut-hb-params'][0];
expect(bid1.bidRequestId).to.equal('263be71e91dd9d');
expect(bid1.sizes.length).to.equal(2);
@@ -150,4 +158,27 @@ describe('Undertone Adapter', function () {
expect(spec.interpretResponse({ body: bidResArray }).length).to.equal(1);
});
});
+
+ describe('getUserSyncs', () => {
+ it('verifies gdpr consent checked', () => {
+ const options = ({ iframeEnabled: true, pixelEnabled: true });
+ expect(spec.getUserSyncs(options, {}, { gdprApplies: true }).length).to.equal(0);
+ });
+
+ it('Verifies sync iframe option', function () {
+ const result = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true });
+ expect(result).to.have.lengthOf(1);
+ expect(result[0].type).to.equal('iframe');
+ expect(result[0].url).to.equal('//cdn.undertone.com/js/usersync.html');
+ });
+
+ it('Verifies sync image option', function () {
+ const result = spec.getUserSyncs({ pixelEnabled: true });
+ expect(result).to.have.lengthOf(2);
+ expect(result[0].type).to.equal('image');
+ expect(result[0].url).to.equal('//usr.undertone.com/userPixel/syncOne?id=1&of=2');
+ expect(result[1].type).to.equal('image');
+ expect(result[1].url).to.equal('//usr.undertone.com/userPixel/syncOne?id=2&of=2');
+ });
+ });
});
From 4c085b8d0f430c6b476a58a19fc29976f638c56a Mon Sep 17 00:00:00 2001
From: Robert Ray Martinez III
Date: Tue, 30 Oct 2018 06:52:03 -0700
Subject: [PATCH 09/62] Updating Auction Init Pick for timestamp + Test update
(#3223)
* Updating Auction Init Pick for timestamp + Test update
* Updating Auction Init to include once again + Rubicon Analytics update accordingly
* Removing from auction init events in favor of old
---
src/auction.js | 2 +-
.../modules/rubiconAnalyticsAdapter_spec.js | 54 ++++++++++++++++++-
2 files changed, 53 insertions(+), 3 deletions(-)
diff --git a/src/auction.js b/src/auction.js
index 61c403e7ff5..221cd519815 100644
--- a/src/auction.js
+++ b/src/auction.js
@@ -110,7 +110,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})
function getProperties() {
return {
auctionId: _auctionId,
- auctionStart: _auctionStart,
+ timestamp: _auctionStart,
auctionEnd: _auctionEnd,
auctionStatus: _auctionStatus,
adUnits: _adUnits,
diff --git a/test/spec/modules/rubiconAnalyticsAdapter_spec.js b/test/spec/modules/rubiconAnalyticsAdapter_spec.js
index fa64513730a..97737675325 100644
--- a/test/spec/modules/rubiconAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rubiconAnalyticsAdapter_spec.js
@@ -106,9 +106,59 @@ const MOCK = {
[BID2.adUnitCode]: BID2.adserverTargeting
},
AUCTION_INIT: {
- 'timestamp': 1519767010567,
'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
- 'timeout': 3000
+ 'timestamp': 1519767010567,
+ 'auctionStatus': 'inProgress',
+ 'adUnits': [ {
+ 'code': '/19968336/header-bid-tag1',
+ 'sizes': [[640, 480]],
+ 'bids': [ {
+ 'bidder': 'rubicon',
+ 'params': {
+ 'accountId': 1001, 'siteId': 113932, 'zoneId': 535512
+ }
+ } ],
+ 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014'
+ }
+ ],
+ 'adUnitCodes': ['/19968336/header-bid-tag1'],
+ 'bidderRequests': [ {
+ 'bidderCode': 'rubicon',
+ 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
+ 'bidderRequestId': '1be65d7958826a',
+ 'bids': [ {
+ 'bidder': 'rubicon',
+ 'params': {
+ 'accountId': 1001, 'siteId': 113932, 'zoneId': 535512
+ },
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [[640, 480]]
+ }
+ },
+ 'adUnitCode': '/19968336/header-bid-tag1',
+ 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014',
+ 'sizes': [[640, 480]],
+ 'bidId': '2ecff0db240757',
+ 'bidderRequestId': '1be65d7958826a',
+ 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
+ 'src': 'client',
+ 'bidRequestsCount': 1
+ }
+ ],
+ 'auctionStart': 1519767010567,
+ 'timeout': 3000,
+ 'refererInfo': {
+ 'referer': 'http://www.test.com/page.html', 'reachedTop': true, 'numIframes': 0, 'stack': ['http://www.test.com/page.html']
+ }
+ }
+ ],
+ 'bidsReceived': [],
+ 'winningBids': [],
+ 'timeout': 3000,
+ 'config': {
+ 'accountId': 1001, 'endpoint': '//localhost:9999/event'
+ }
},
BID_REQUESTED: {
'bidder': 'rubicon',
From 50d509764e6b1d81903c9f00a8ac0524131a397b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=83=A1=E9=9B=A8=E8=BB=92=20=D0=9F=D0=B5=D1=82=D1=80?=
Date: Tue, 30 Oct 2018 15:47:21 +0100
Subject: [PATCH 10/62] Add code, test, and doc for Adikteev adapter (#3229)
* Add code, test, and doc for Adikteev adapter
* Reflect comments on other PR
http://prebid.org/dev-docs/bidder-adaptor.html#referrers
https://github.com/prebid/Prebid.js/pull/3230#discussion_r228319752
* 'currency' isn't a bidder-specific param
Update PR following this remark on another one:
https://github.com/prebid/Prebid.js/pull/3228#discussion_r228317072
* Add integration example, fix bid requestId
---
.../gpt/hello_world_adikteev.html | 93 +++++++
integrationExamples/gpt/pbjs_example_gpt.html | 11 +-
modules/adikteevBidAdapter.js | 94 +++++++
modules/adikteevBidAdapter.md | 35 +++
test/spec/modules/adikteevBidAdapter_spec.js | 235 ++++++++++++++++++
5 files changed, 466 insertions(+), 2 deletions(-)
create mode 100644 integrationExamples/gpt/hello_world_adikteev.html
create mode 100644 modules/adikteevBidAdapter.js
create mode 100644 modules/adikteevBidAdapter.md
create mode 100644 test/spec/modules/adikteevBidAdapter_spec.js
diff --git a/integrationExamples/gpt/hello_world_adikteev.html b/integrationExamples/gpt/hello_world_adikteev.html
new file mode 100644
index 00000000000..7372ff12d7f
--- /dev/null
+++ b/integrationExamples/gpt/hello_world_adikteev.html
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+Basic Prebid.js Example
+Div-1
+
+
+
+
+
+
diff --git a/integrationExamples/gpt/pbjs_example_gpt.html b/integrationExamples/gpt/pbjs_example_gpt.html
index 88d4839d984..6852b9f680a 100644
--- a/integrationExamples/gpt/pbjs_example_gpt.html
+++ b/integrationExamples/gpt/pbjs_example_gpt.html
@@ -312,8 +312,15 @@
width: '300',
height: '250',
}
- }
-
+ },
+ {
+ bidder: 'adikteev',
+ params: {
+ placementId: 12345,
+ currency: 'EUR',
+ bidFloorPrice: 0.1,
+ }
+ },
]
}, {
code: 'div-gpt-ad-12345678-1',
diff --git a/modules/adikteevBidAdapter.js b/modules/adikteevBidAdapter.js
new file mode 100644
index 00000000000..12d502de94a
--- /dev/null
+++ b/modules/adikteevBidAdapter.js
@@ -0,0 +1,94 @@
+import {registerBidder} from 'src/adapters/bidderFactory';
+import {BANNER} from 'src/mediaTypes';
+import * as utils from '../src/utils';
+import {config} from 'src/config';
+
+export const BIDDER_CODE = 'adikteev';
+export const ENDPOINT_URL = 'https://serve-adserver.adikteev.com/api/prebid/bid';
+export const ENDPOINT_URL_STAGING = 'https://serve-adserver-staging.adikteev.com/api/prebid/bid';
+export const USER_SYNC_IFRAME_URL = 'https://serve-adserver.adikteev.com/api/prebid/sync-iframe';
+export const USER_SYNC_IFRAME_URL_STAGING = 'https://serve-adserver-staging.adikteev.com/api/prebid/sync-iframe';
+export const USER_SYNC_IMAGE_URL = 'https://serve-adserver.adikteev.com/api/prebid/sync-image';
+export const USER_SYNC_IMAGE_URL_STAGING = 'https://serve-adserver-staging.adikteev.com/api/prebid/sync-image';
+
+export let stagingEnvironmentSwitch = false; // Don't use it. Allow us to make tests on staging
+
+export function setstagingEnvironmentSwitch(value) {
+ stagingEnvironmentSwitch = value;
+}
+
+function validateSizes(sizes) {
+ if (!utils.isArray(sizes) || typeof sizes[0] === 'undefined') {
+ return false;
+ }
+ return sizes.every(size => utils.isArray(size) && size.length === 2);
+}
+
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: [BANNER],
+
+ isBidRequestValid: (bid) => {
+ setstagingEnvironmentSwitch(stagingEnvironmentSwitch || !!bid.params.stagingEnvironment);
+ return !!(
+ bid &&
+ bid.params &&
+ bid.params.bidFloorPrice &&
+ bid.params.placementId &&
+ bid.bidder === BIDDER_CODE &&
+ validateSizes(bid.mediaTypes.banner.sizes)
+ );
+ },
+
+ buildRequests: (validBidRequests, bidderRequest) => {
+ const payload = {
+ validBidRequests,
+ bidderRequest,
+ refererInfo: bidderRequest.refererInfo,
+ currency: config.getConfig('currency'),
+ userAgent: navigator.userAgent,
+ screen: {
+ width: window.screen.width,
+ height: window.screen.height
+ },
+ language: navigator.language,
+ cookies: document.cookie.split(';'),
+ prebidUpdateVersion: '1.29.0',
+ };
+ return {
+ method: 'POST',
+ url: stagingEnvironmentSwitch ? ENDPOINT_URL_STAGING : ENDPOINT_URL,
+ data: JSON.stringify(payload),
+ };
+ },
+
+ interpretResponse: (serverResponse, bidRequests) => {
+ const returnedBids = [];
+ const validBidRequests = JSON.parse(bidRequests.data).validBidRequests;
+ serverResponse.body.forEach((value, index) => {
+ const overrides = {
+ requestId: validBidRequests[index].bidId,
+ };
+ returnedBids.push(Object.assign({}, value, overrides));
+ });
+ return returnedBids;
+ },
+
+ getUserSyncs: (syncOptions, serverResponses) => {
+ const syncs = [];
+ if (syncOptions.iframeEnabled) {
+ syncs.push({
+ type: 'iframe',
+ url: stagingEnvironmentSwitch ? USER_SYNC_IFRAME_URL_STAGING : USER_SYNC_IFRAME_URL,
+ });
+ }
+ if (syncOptions.pixelEnabled && serverResponses.length > 0) {
+ syncs.push({
+ type: 'image',
+ url: stagingEnvironmentSwitch ? USER_SYNC_IMAGE_URL_STAGING : USER_SYNC_IMAGE_URL,
+ });
+ }
+ return syncs;
+ },
+};
+registerBidder(spec);
diff --git a/modules/adikteevBidAdapter.md b/modules/adikteevBidAdapter.md
new file mode 100644
index 00000000000..d5008f61b03
--- /dev/null
+++ b/modules/adikteevBidAdapter.md
@@ -0,0 +1,35 @@
+# Overview
+
+```
+Module Name: Adikteev Bidder Adapter
+Module Type: Bidder Adapter
+Maintainer: adnetwork@adikteev.com
+```
+
+# Description
+
+Module that connects to Adikteev's demand sources
+
+# Test Parameters
+
+``` javascript
+ var adUnits = [
+ {
+ code: 'test-div',
+ mediaTypes: {
+ banner: {
+ sizes: [[750, 200]], // a display size
+ }
+ },
+ bids: [
+ {
+ bidder: 'adikteev',
+ params: {
+ placementId: 12345,
+ bidFloorPrice: 0.1,
+ }
+ }
+ ]
+ }
+ ];
+```
diff --git a/test/spec/modules/adikteevBidAdapter_spec.js b/test/spec/modules/adikteevBidAdapter_spec.js
new file mode 100644
index 00000000000..243cbe2a9c5
--- /dev/null
+++ b/test/spec/modules/adikteevBidAdapter_spec.js
@@ -0,0 +1,235 @@
+import {expect} from 'chai';
+import {
+ ENDPOINT_URL,
+ ENDPOINT_URL_STAGING,
+ setstagingEnvironmentSwitch,
+ spec,
+ stagingEnvironmentSwitch,
+ USER_SYNC_IFRAME_URL,
+ USER_SYNC_IFRAME_URL_STAGING,
+ USER_SYNC_IMAGE_URL,
+ USER_SYNC_IMAGE_URL_STAGING,
+} from 'modules/adikteevBidAdapter';
+import {newBidder} from 'src/adapters/bidderFactory';
+import * as utils from '../../../src/utils';
+
+describe('adikteevBidAdapter', () => {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', () => {
+ it('exists and is a function', () => {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ it('exists and is a function', () => {
+ expect(setstagingEnvironmentSwitch).to.exist.and.to.be.a('function');
+ });
+ it('exists and is correctly set', () => {
+ expect(stagingEnvironmentSwitch).to.exist.and.to.equal(false);
+ });
+ });
+
+ describe('isBidRequestValid', () => {
+ it('should return true when required params found', () => {
+ const validBid = {
+ bidder: 'adikteev',
+ params: {
+ placementId: 12345,
+ bidFloorPrice: 0.1,
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[750, 200]]
+ }
+ },
+ };
+ expect(spec.isBidRequestValid(validBid)).to.equal(true);
+ });
+
+ it('should mutate stagingEnvironmentSwitch when required params found', () => {
+ const withstagingEnvironmentSwitch = {
+ params: {
+ stagingEnvironment: true,
+ },
+ };
+ spec.isBidRequestValid(withstagingEnvironmentSwitch);
+ expect(stagingEnvironmentSwitch).to.equal(true);
+ setstagingEnvironmentSwitch(false);
+ });
+
+ it('should return false when required params are invalid', () => {
+ expect(spec.isBidRequestValid({
+ bidder: '', // invalid bidder
+ params: {
+ placementId: 12345,
+ bidFloorPrice: 0.1,
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[750, 200]]
+ }
+ },
+ })).to.equal(false);
+ expect(spec.isBidRequestValid({
+ bidder: 'adikteev',
+ params: {
+ placementId: '', // invalid placementId
+ bidFloorPrice: 0.1,
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[750, 200]]
+ }
+ },
+ })).to.equal(false);
+ expect(spec.isBidRequestValid({
+ bidder: 'adikteev',
+ params: {
+ placementId: 12345,
+ bidFloorPrice: 0.1,
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[750]] // invalid size
+ }
+ },
+ })).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', () => {
+ const validBidRequests = [];
+ const bidderRequest = {};
+ const serverRequest = spec.buildRequests(validBidRequests, bidderRequest);
+ it('creates a request object with correct method, url and data', () => {
+ expect(serverRequest).to.exist.and.have.all.keys(
+ 'method',
+ 'url',
+ 'data',
+ );
+ expect(serverRequest.method).to.equal('POST');
+ expect(serverRequest.url).to.equal(ENDPOINT_URL);
+
+ let requestData = JSON.parse(serverRequest.data);
+ expect(requestData).to.exist.and.have.all.keys(
+ 'validBidRequests',
+ 'bidderRequest',
+ 'userAgent',
+ 'screen',
+ 'language',
+ 'cookies',
+ // 'refererInfo',
+ // 'currency',
+ 'prebidUpdateVersion',
+ );
+ expect(requestData.validBidRequests).to.deep.equal(validBidRequests);
+ expect(requestData.bidderRequest).to.deep.equal(bidderRequest);
+ expect(requestData.userAgent).to.deep.equal(navigator.userAgent);
+ expect(requestData.screen.width).to.deep.equal(window.screen.width);
+ expect(requestData.screen.height).to.deep.equal(window.screen.height);
+ expect(requestData.language).to.deep.equal(navigator.language);
+ expect(requestData.prebidUpdateVersion).to.deep.equal('1.29.0');
+ });
+
+ describe('staging environment', () => {
+ setstagingEnvironmentSwitch(true);
+ const serverRequest = spec.buildRequests(validBidRequests, bidderRequest);
+ expect(serverRequest.url).to.equal(ENDPOINT_URL_STAGING);
+ setstagingEnvironmentSwitch(false);
+ });
+ });
+
+ describe('interpretResponse', () => {
+ it('bid objects from response', () => {
+ const serverResponse =
+ {
+ body: [
+ {
+ cpm: 1,
+ width: 300,
+ height: 250,
+ ad: '',
+ ttl: 360,
+ creativeId: 123,
+ netRevenue: false,
+ currency: 'EUR',
+ }
+ ]
+ };
+ const payload = {
+ validBidRequests: [{
+ bidId: '2ef7bb021ac847'
+ }],
+ };
+ const bidRequests = {
+ method: 'POST',
+ url: stagingEnvironmentSwitch ? ENDPOINT_URL_STAGING : ENDPOINT_URL,
+ data: JSON.stringify(payload),
+ };
+ const bidResponses = spec.interpretResponse(serverResponse, bidRequests);
+ expect(bidResponses).to.be.an('array').that.is.not.empty; // yes, syntax is correct
+ expect(bidResponses[0]).to.have.all.keys(
+ 'requestId',
+ 'cpm',
+ 'width',
+ 'height',
+ 'ad',
+ 'ttl',
+ 'creativeId',
+ 'netRevenue',
+ 'currency',
+ );
+
+ expect(bidResponses[0].requestId).to.equal(payload.validBidRequests[0].bidId);
+ expect(bidResponses[0].cpm).to.equal(serverResponse.body[0].cpm);
+ expect(bidResponses[0].width).to.equal(serverResponse.body[0].width);
+ expect(bidResponses[0].height).to.equal(serverResponse.body[0].height);
+ expect(bidResponses[0].ad).to.equal(serverResponse.body[0].ad);
+ expect(bidResponses[0].ttl).to.equal(serverResponse.body[0].ttl);
+ expect(bidResponses[0].creativeId).to.equal(serverResponse.body[0].creativeId);
+ expect(bidResponses[0].netRevenue).to.equal(serverResponse.body[0].netRevenue);
+ expect(bidResponses[0].currency).to.equal(serverResponse.body[0].currency);
+ });
+ });
+
+ describe('getUserSyncs', () => {
+ expect(spec.getUserSyncs({
+ iframeEnabled: true
+ }, [{}])).to.deep.equal([{
+ type: 'iframe',
+ url: USER_SYNC_IFRAME_URL
+ }]);
+
+ expect(spec.getUserSyncs({
+ pixelEnabled: true
+ }, [{}])).to.deep.equal([{
+ type: 'image',
+ url: USER_SYNC_IMAGE_URL
+ }]);
+
+ expect(spec.getUserSyncs({
+ iframeEnabled: true,
+ pixelEnabled: true
+ }, [{}])).to.deep.equal([{
+ type: 'iframe',
+ url: USER_SYNC_IFRAME_URL
+ }, {
+ type: 'image',
+ url: USER_SYNC_IMAGE_URL
+ }]);
+
+ describe('staging environment', () => {
+ setstagingEnvironmentSwitch(true);
+ expect(spec.getUserSyncs({
+ iframeEnabled: true,
+ pixelEnabled: true
+ }, [{}])).to.deep.equal([{
+ type: 'iframe',
+ url: USER_SYNC_IFRAME_URL_STAGING
+ }, {
+ type: 'image',
+ url: USER_SYNC_IMAGE_URL_STAGING
+ }]);
+ setstagingEnvironmentSwitch(false);
+ });
+ });
+});
From 9ddb20b689f65c4305de7129163a7d2308bfc868 Mon Sep 17 00:00:00 2001
From: jacekburys-quantcast
<44467819+jacekburys-quantcast@users.noreply.github.com>
Date: Tue, 30 Oct 2018 14:49:27 +0000
Subject: [PATCH 11/62] Quantcast adapter onTimeout (#3239)
* onTimeout WIP
* test for onTimeout
* some renaming
* cleanup
* cleanup
* trying to fix the test
* using ajax instead of fetch
---
modules/quantcastBidAdapter.js | 7 ++++++-
test/spec/modules/quantcastBidAdapter_spec.js | 17 +++++++++++++++++
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/modules/quantcastBidAdapter.js b/modules/quantcastBidAdapter.js
index e6f4d27bdbb..79128a834a4 100644
--- a/modules/quantcastBidAdapter.js
+++ b/modules/quantcastBidAdapter.js
@@ -1,4 +1,5 @@
import * as utils from 'src/utils';
+import { ajax } from 'src/ajax';
import { registerBidder } from 'src/adapters/bidderFactory';
const BIDDER_CODE = 'quantcast';
@@ -69,7 +70,7 @@ export const spec = {
});
});
- const gdprConsent = bidderRequest ? bidderRequest.gdprConsent : {};
+ const gdprConsent = (bidderRequest && bidderRequest.gdprConsent) ? bidderRequest.gdprConsent : {};
// Request Data Format can be found at https://wiki.corp.qc/display/adinf/QCX
const requestData = {
@@ -157,6 +158,10 @@ export const spec = {
});
return bidResponsesList;
+ },
+ onTimeout(timeoutData) {
+ const url = `${QUANTCAST_PROTOCOL}://${QUANTCAST_DOMAIN}:${QUANTCAST_PORT}/qchb_notify?type=timeout`;
+ ajax(url, null, null);
}
};
diff --git a/test/spec/modules/quantcastBidAdapter_spec.js b/test/spec/modules/quantcastBidAdapter_spec.js
index f5a7602c7ab..e64294e87e2 100644
--- a/test/spec/modules/quantcastBidAdapter_spec.js
+++ b/test/spec/modules/quantcastBidAdapter_spec.js
@@ -1,5 +1,6 @@
import * as utils from 'src/utils';
import { expect } from 'chai';
+import { stub, sandbox } from 'sinon';
import {
QUANTCAST_DOMAIN,
QUANTCAST_TEST_DOMAIN,
@@ -12,6 +13,7 @@ import {
} from '../../../modules/quantcastBidAdapter';
import { newBidder } from '../../../src/adapters/bidderFactory';
import { parse } from 'src/url';
+import * as ajax from 'src/ajax';
describe('Quantcast adapter', function () {
const quantcastAdapter = newBidder(qcSpec);
@@ -211,4 +213,19 @@ describe('Quantcast adapter', function () {
expect(interpretedResponse.length).to.equal(0);
});
});
+
+ describe('`onTimeout`', function() {
+ it('makes a request to the notify endpoint', function() {
+ const sinonSandbox = sandbox.create();
+ const ajaxStub = sinonSandbox.stub(ajax, 'ajax').callsFake(function() {});
+ const timeoutData = {
+ bidder: 'quantcast'
+ };
+ qcSpec.onTimeout(timeoutData);
+ const expectedUrl = `${QUANTCAST_PROTOCOL}://${QUANTCAST_DOMAIN}:${QUANTCAST_PORT}/qchb_notify?type=timeout`;
+ ajaxStub.withArgs(expectedUrl, null, null).calledOnce.should.be.true;
+ ajaxStub.restore();
+ sinonSandbox.restore();
+ });
+ });
});
From 903743a20fb721428851413491e75ff271261e3a Mon Sep 17 00:00:00 2001
From: Rich Snapp
Date: Tue, 30 Oct 2018 09:30:48 -0600
Subject: [PATCH 12/62] Test cleanup (#3238)
* stub pixel call in justpremium tests
* properly stub geolocation services to prevent prompts
* stub img creation as well to prevent call in justpremium
---
modules/justpremiumBidAdapter.js | 16 ++--
.../modules/justpremiumBidAdapter_spec.js | 20 ++++-
test/spec/modules/uolBidAdapter_spec.js | 75 +++++++++----------
3 files changed, 63 insertions(+), 48 deletions(-)
diff --git a/modules/justpremiumBidAdapter.js b/modules/justpremiumBidAdapter.js
index 48b6805c0e1..c31f485020e 100644
--- a/modules/justpremiumBidAdapter.js
+++ b/modules/justpremiumBidAdapter.js
@@ -122,6 +122,16 @@ export const spec = {
}
+export let pixel = {
+ fire(url) {
+ let img = document.createElement('img')
+ img.src = url
+ img.id = 'jp-pixel-track'
+ img.style.cssText = 'display:none !important;'
+ document.body.appendChild(img)
+ }
+};
+
function track (data, payload, type) {
let pubUrl = ''
@@ -147,11 +157,7 @@ ru=${encodeURIComponent(pubUrl)}&tt=&siw=&sh=${payload.sh}&sw=${payload.sw}&wh=$
sd=&_c=&et=&aid=&said=&ei=&fc=&sp=&at=bidder&cid=&ist=&mg=&dl=&dlt=&ev=&vt=&zid=${payload.id}&dr=${duration}&di=&pr=&
cw=&ch=&nt=&st=&jp=${encodeURIComponent(JSON.stringify(jp))}&ty=${type}`
- let img = document.createElement('img')
- img.src = pixelUrl
- img.id = 'jp-pixel-track'
- img.style.cssText = 'display:none !important;'
- document.body.appendChild(img)
+ pixel.fire(pixelUrl);
}
function findBid (params, bids) {
diff --git a/test/spec/modules/justpremiumBidAdapter_spec.js b/test/spec/modules/justpremiumBidAdapter_spec.js
index 3c1048143d2..8167c29e5c2 100644
--- a/test/spec/modules/justpremiumBidAdapter_spec.js
+++ b/test/spec/modules/justpremiumBidAdapter_spec.js
@@ -1,7 +1,19 @@
import { expect } from 'chai'
-import { spec } from 'modules/justpremiumBidAdapter'
+import { spec, pixel } from 'modules/justpremiumBidAdapter'
describe('justpremium adapter', function () {
+ let sandbox;
+ let pixelStub;
+
+ beforeEach(function() {
+ sandbox = sinon.sandbox.create();
+ pixelStub = sandbox.stub(pixel, 'fire');
+ });
+
+ afterEach(function() {
+ sandbox.restore();
+ });
+
let adUnits = [
{
adUnitCode: 'div-gpt-ad-1471513102552-1',
@@ -132,7 +144,7 @@ describe('justpremium adapter', function () {
})
describe('onTimeout', function () {
- it('onTimeout', (done) => {
+ it('onTimeout', function(done) {
spec.onTimeout([{
'bidId': '25cd3ec3fd6ed7',
'bidder': 'justpremium',
@@ -153,7 +165,9 @@ describe('justpremium adapter', function () {
'zone': 21521
}],
'timeout': 1
- }])
+ }]);
+
+ expect(pixelStub.calledOnce).to.equal(true);
done()
})
diff --git a/test/spec/modules/uolBidAdapter_spec.js b/test/spec/modules/uolBidAdapter_spec.js
index 1733afc91f9..e9341772e7d 100644
--- a/test/spec/modules/uolBidAdapter_spec.js
+++ b/test/spec/modules/uolBidAdapter_spec.js
@@ -1,11 +1,20 @@
import { expect } from 'chai';
import { spec } from 'modules/uolBidAdapter';
-import { newBidder } from 'src/adapters/bidderFactory';
const ENDPOINT = 'https://prebid.adilligo.com/v1/prebid.json';
describe('UOL Bid Adapter', function () {
- const adapter = newBidder(spec);
+ let sandbox;
+ let queryStub;
+ let getCurrentPositionStub;
+
+ beforeEach(function() {
+ sandbox = sinon.sandbox.create();
+ });
+
+ afterEach(function() {
+ sandbox.restore();
+ });
describe('isBidRequestValid', function () {
let bid = {
@@ -88,31 +97,6 @@ describe('UOL Bid Adapter', function () {
});
describe('buildRequests', function () {
- let queryPermission;
- let cleanup = function() {
- navigator.permissions.query = queryPermission;
- };
- let grantTriangulation = function() {
- queryPermission = navigator.permissions.query;
- navigator.permissions.query = function(data) {
- return new Promise((resolve, reject) => {
- resolve({state: 'granted'});
- });
- }
- };
- let denyTriangulation = function() {
- queryPermission = navigator.permissions.query;
- navigator.permissions.query = function(data) {
- return new Promise((resolve, reject) => {
- resolve({state: 'prompt'});
- });
- }
- };
- let removeQuerySupport = function() {
- queryPermission = navigator.permissions.query;
- navigator.permissions.query = undefined;
- }
-
let bidRequests = [
{
'bidder': 'uol',
@@ -173,31 +157,42 @@ describe('UOL Bid Adapter', function () {
describe('buildRequest geolocation param', function () { // shall only be tested if browser engine supports geolocation and permissions API.
let geolocation = { lat: 4, long: 3, timestamp: 123121451 };
- it('should contain user coordinates if (i) DNT is off; (ii) browser supports implementation; (iii) localStorage contains geolocation history', function () {
+ beforeEach(function() {
+ getCurrentPositionStub = sandbox.stub(navigator.geolocation, 'getCurrentPosition');
+ queryStub = sandbox.stub(navigator.permissions, 'query');
+ });
+
+ it('should not contain user coordinates if browser doesnt support permission query', function () {
localStorage.setItem('uolLocationTracker', JSON.stringify(geolocation));
- grantTriangulation();
+ navigator.permissions.query = undefined;
const requestObject = spec.buildRequests(bidRequests, bidderRequest);
const payload = JSON.parse(requestObject.data);
- expect(payload.geolocation).to.exist.and.not.be.empty;
- cleanup();
+ expect(payload.geolocation).to.not.exist;
})
- it('should not contain user coordinates if localStorage is empty', function () {
- localStorage.removeItem('uolLocationTracker');
- denyTriangulation();
+ it('should contain user coordinates if (i) DNT is off; (ii) browser supports implementation; (iii) localStorage contains geolocation history', function (done) {
+ localStorage.setItem('uolLocationTracker', JSON.stringify(geolocation));
+ queryStub.callsFake(function() {
+ return new Promise((resolve, reject) => {
+ resolve({state: 'granted'});
+ });
+ });
+ getCurrentPositionStub.callsFake(() => done());
const requestObject = spec.buildRequests(bidRequests, bidderRequest);
const payload = JSON.parse(requestObject.data);
- expect(payload.geolocation).to.not.exist;
- cleanup();
+ expect(payload.geolocation).to.exist.and.not.be.empty;
})
- it('should not contain user coordinates if browser doesnt support permission query', function () {
- localStorage.setItem('uolLocationTracker', JSON.stringify(geolocation));
- removeQuerySupport();
+ it('should not contain user coordinates if localStorage is empty', function () {
+ localStorage.removeItem('uolLocationTracker');
+ queryStub.callsFake(function() {
+ return new Promise((resolve, reject) => {
+ resolve({state: 'prompt'});
+ });
+ });
const requestObject = spec.buildRequests(bidRequests, bidderRequest);
const payload = JSON.parse(requestObject.data);
expect(payload.geolocation).to.not.exist;
- cleanup();
})
})
}
From 0de2478f8f94ebfa5fcc802673b65b4d33989ba5 Mon Sep 17 00:00:00 2001
From: Jaimin Panchal
Date: Tue, 30 Oct 2018 11:32:27 -0400
Subject: [PATCH 13/62] Appnexus adapter: Added dealPriority and dealCode to
bidResponse (#3201)
* Added dealPriority and dealCode to appnexus adapter
* update failed test
* added namespace and did deep merge
* keep all properties together
---
modules/appnexusBidAdapter.js | 4 +++-
test/spec/modules/appnexusBidAdapter_spec.js | 10 ++++++++++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js
index aaec207dc1e..19aa5e7cf73 100644
--- a/modules/appnexusBidAdapter.js
+++ b/modules/appnexusBidAdapter.js
@@ -233,7 +233,9 @@ function newBid(serverBid, rtbBid, bidderRequest) {
netRevenue: true,
ttl: 300,
appnexus: {
- buyerMemberId: rtbBid.buyer_member_id
+ buyerMemberId: rtbBid.buyer_member_id,
+ dealPriority: rtbBid.deal_priority,
+ dealCode: rtbBid.deal_code
}
};
diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js
index 9be87ac8628..5e41c1c9544 100644
--- a/test/spec/modules/appnexusBidAdapter_spec.js
+++ b/test/spec/modules/appnexusBidAdapter_spec.js
@@ -561,5 +561,15 @@ describe('AppNexusAdapter', function () {
bidderRequest.bids[0].renderer.options
);
});
+
+ it('should add deal_priority and deal_code', function() {
+ let responseWithDeal = deepClone(response);
+ responseWithDeal.tags[0].ads[0].deal_priority = 'high';
+ responseWithDeal.tags[0].ads[0].deal_code = '123';
+
+ let bidderRequest;
+ let result = spec.interpretResponse({ body: responseWithDeal }, {bidderRequest});
+ expect(Object.keys(result[0].appnexus)).to.include.members(['buyerMemberId', 'dealPriority', 'dealCode']);
+ });
});
});
From 5481af902483506628302dbf0659bf1ccd7f1f21 Mon Sep 17 00:00:00 2001
From: HolzAndrew
Date: Tue, 30 Oct 2018 13:32:25 -0400
Subject: [PATCH 14/62] use unit id being sent instead of hard coded auid
(#3236)
* use unit id being sent instead of hard coded auid
* make multiple requests
* removes commented out code. adds aus param back
---
modules/openxoutstreamBidAdapter.js | 47 +++++++---------
modules/openxoutstreamBidAdapter.md | 3 +-
.../modules/openxoutstreamBidAdapter_spec.js | 54 +++++++++----------
3 files changed, 48 insertions(+), 56 deletions(-)
diff --git a/modules/openxoutstreamBidAdapter.js b/modules/openxoutstreamBidAdapter.js
index dde101f25d5..aee260e0a11 100644
--- a/modules/openxoutstreamBidAdapter.js
+++ b/modules/openxoutstreamBidAdapter.js
@@ -20,28 +20,21 @@ export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: SUPPORTED_AD_TYPES,
isBidRequestValid: function(bidRequest) {
- if (bidRequest.params.delDomain) {
- return !!bidRequest.params.unit || utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes.length') > 0;
- }
- return false;
+ return !!(bidRequest.params.delDomain && bidRequest.params.unit)
},
buildRequests: function(bidRequests, bidderRequest) {
if (bidRequests.length === 0) {
return [];
}
let requests = [];
- requests.push(buildOXBannerRequest(bidRequests, bidderRequest));
+ bidRequests.forEach(bid => {
+ requests.push(buildOXBannerRequest(bid, bidderRequest));
+ })
return requests;
},
- interpretResponse: function(serverResponse, serverRequest) {
- return handleVastResponse(serverResponse, serverRequest.payload)
+ interpretResponse: function(bid, serverResponse) {
+ return handleVastResponse(bid, serverResponse.payload)
},
-
- transformBidParams: function(params, isOpenRtb) {
- return utils.convertTypes({
- 'unit': 'string',
- }, params);
- }
};
function getViewportDimensions(isIfr) {
@@ -70,7 +63,7 @@ function getViewportDimensions(isIfr) {
return `${width}x${height}`;
}
-function buildCommonQueryParamsFromBids(bids, bidderRequest) {
+function buildCommonQueryParamsFromBids(bid, bidderRequest) {
const isInIframe = utils.inIframe();
let defaultParams;
defaultParams = {
@@ -82,13 +75,13 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
tz: new Date().getTimezoneOffset(),
tws: getViewportDimensions(isInIframe),
be: 1,
- bc: bids[0].params.bc || `${BIDDER_CONFIG}_${BIDDER_VERSION}`,
- auid: '540141567',
- dddid: utils._map(bids, bid => bid.transactionId).join(','),
+ bc: bid.params.bc || `${BIDDER_CONFIG}_${BIDDER_VERSION}`,
+ auid: bid.params.unit,
+ dddid: bid.transactionId,
openrtb: '%7B%22mimes%22%3A%5B%22video%2Fmp4%22%5D%7D',
nocache: new Date().getTime(),
- vht: bids[0].params.height || bids[0].sizes[0][1],
- vwd: bids[0].params.width || bids[0].sizes[0][0]
+ vht: bid.params.height || bid.sizes[0][1],
+ vwd: bid.params.width || bid.sizes[0][0]
};
if (utils.deepAccess(bidderRequest, 'gdprConsent')) {
@@ -110,24 +103,24 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
return defaultParams;
}
-function buildOXBannerRequest(bids, bidderRequest) {
- let queryParams = buildCommonQueryParamsFromBids(bids, bidderRequest);
- queryParams.aus = utils._map(bids, bid => utils.parseSizesInput(bid.sizes).join(',')).join('|');
+function buildOXBannerRequest(bid, bidderRequest) {
+ let queryParams = buildCommonQueryParamsFromBids(bid, bidderRequest);
+ queryParams.aus = utils.parseSizesInput(bid.sizes).join(',');
- if (bids.some(bid => bid.params.doNotTrack)) {
+ if (bid.params.doNotTrack) {
queryParams.ns = 1;
}
- if (bids.some(bid => bid.params.coppa)) {
+ if (bid.params.coppa) {
queryParams.tfcd = 1;
}
- let url = `https://${bids[0].params.delDomain}/v/1.0/avjp`
+ let url = `https://${bid.params.delDomain}/v/1.0/avjp`
return {
method: 'GET',
url: url,
data: queryParams,
- payload: {'bids': bids}
+ payload: {'bid': bid}
};
}
@@ -146,7 +139,7 @@ function handleVastResponse(response, serverResponse) {
const ymAdsScript = '';
let bidResponse = {};
- bidResponse.requestId = serverResponse.bids[0].bidId;
+ bidResponse.requestId = serverResponse.bid.bidId;
bidResponse.bidderCode = BIDDER_CODE;
bidResponse.netRevenue = NET_REVENUE;
bidResponse.currency = CURRENCY;
diff --git a/modules/openxoutstreamBidAdapter.md b/modules/openxoutstreamBidAdapter.md
index a77b4560f97..16d66b92409 100644
--- a/modules/openxoutstreamBidAdapter.md
+++ b/modules/openxoutstreamBidAdapter.md
@@ -24,9 +24,8 @@ var adUnits = [
{
bidder: 'openxoutstream',
params: {
- unit: '53943996499',
+ unit: '540141567',
delDomain: 'se-demo-d.openx.net',
- publisher_page_url: 'yieldmo.com',
width: '300',
height: '250',
}
diff --git a/test/spec/modules/openxoutstreamBidAdapter_spec.js b/test/spec/modules/openxoutstreamBidAdapter_spec.js
index 59d56bee74b..9b189856e1a 100644
--- a/test/spec/modules/openxoutstreamBidAdapter_spec.js
+++ b/test/spec/modules/openxoutstreamBidAdapter_spec.js
@@ -44,28 +44,23 @@ describe('OpenXOutstreamAdapter', function () {
bannerBid.params = {delDomain: 'test-delivery-domain'}
});
- it('should return false when there is no ad unit id and size', function () {
+ it('should return false if there is no adunit id and sizes are defined', function () {
+ bannerBid.mediaTypes.banner.sizes = [720, 90];
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
});
- it('should return true if there is an adunit id ', function () {
+ it('should return true if there is delivery domain and unit', function () {
bannerBid.params.unit = '12345678';
expect(spec.isBidRequestValid(bannerBid)).to.equal(true);
});
-
- it('should return true if there is no adunit id and sizes are defined', function () {
- bannerBid.mediaTypes.banner.sizes = [720, 90];
- expect(spec.isBidRequestValid(bannerBid)).to.equal(true);
- });
-
- it('should return false if no sizes are defined ', function () {
+ it('should return false if there is unit but no delivery domain', function () {
+ bannerBid.params = {unit: '12345678'};
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
});
-
- it('should return false if sizes empty ', function () {
- bannerBid.mediaTypes.banner.sizes = [];
+ it('shoud return false if there is no delivery domain and no unit', function () {
+ bannerBid.params = {};
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
- });
+ })
});
});
});
@@ -92,40 +87,45 @@ describe('OpenXOutstreamAdapter', function () {
expect(request[0].method).to.equal('GET');
});
- it('should send ad unit ids when any are defined', function () {
+ it('should send ad unit ids, height, and width when any are defined', function () {
const bidRequestsWithUnitIds = [{
'bidder': BIDDER,
'params': {
+ 'unit': '540141567',
+ 'height': '300',
+ 'width': '250',
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
- 'sizes': [300, 250],
+ sizes: [300, 250],
mediaTypes: {
banner: {
- sizes: [[300, 250], [300, 600]]
+ sizes: [[728, 90]]
}
},
- 'bidId': 'test-bid-id-1',
- 'bidderRequestId': 'test-bid-request-1',
- 'auctionId': 'test-auction-1'
+ 'bidId': 'test-bid-id-2',
+ 'bidderRequestId': 'test-bid-request-2',
+ 'auctionId': 'test-auction-2'
}, {
'bidder': BIDDER,
'params': {
- 'unit': '540141567',
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
+ 'sizes': [300, 250],
mediaTypes: {
banner: {
- sizes: [[728, 90]]
+ sizes: [[300, 250], [300, 600]]
}
},
- 'bidId': 'test-bid-id-2',
- 'bidderRequestId': 'test-bid-request-2',
- 'auctionId': 'test-auction-2'
+ 'bidId': 'test-bid-id-1',
+ 'bidderRequestId': 'test-bid-request-1',
+ 'auctionId': 'test-auction-1'
}];
const request = spec.buildRequests(bidRequestsWithUnitIds);
- expect(request[0].data.auid).to.equal(`${bidRequestsWithUnitIds[1].params.unit}`);
+ expect(request[0].data.auid).to.equal(`${bidRequestsWithUnitIds[0].params.unit}`);
+ expect(request[0].data.vht).to.equal(`${bidRequestsWithUnitIds[0].params.height}`);
+ expect(request[0].data.vwd).to.equal(`${bidRequestsWithUnitIds[0].params.width}`);
});
describe('interpretResponse', function () {
@@ -147,9 +147,9 @@ describe('OpenXOutstreamAdapter', function () {
};
serverRequest = {
payload: {
- bids: [{
+ bid: {
bidId: '2d36ac90d654af',
- }],
+ },
}
};
});
From 6649ef96ec224cb861e23a2fe8891a9073fd49e8 Mon Sep 17 00:00:00 2001
From: Jason Snellbaker
Date: Tue, 30 Oct 2018 14:34:12 -0400
Subject: [PATCH 15/62] Prebid 1.30.0 Release
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index a53085fa062..542c14f3525 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "prebid.js",
- "version": "1.30.0-pre",
+ "version": "1.30.0",
"description": "Header Bidding Management Library",
"main": "src/prebid.js",
"scripts": {
From ab703accc628d2dcf888125c818bf925ffa77ab2 Mon Sep 17 00:00:00 2001
From: Jason Snellbaker
Date: Tue, 30 Oct 2018 14:50:06 -0400
Subject: [PATCH 16/62] increment pre version
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 542c14f3525..288d970f842 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "prebid.js",
- "version": "1.30.0",
+ "version": "1.31.0-pre",
"description": "Header Bidding Management Library",
"main": "src/prebid.js",
"scripts": {
From 2c5685cb271c364478113546cef471c11499ec06 Mon Sep 17 00:00:00 2001
From: Rich Snapp
Date: Wed, 31 Oct 2018 07:52:28 -0600
Subject: [PATCH 17/62] fix deal targeting for cpm 0 (#3233)
---
src/targeting.js | 13 +----
test/spec/unit/core/targeting_spec.js | 78 ++++++++++++++++-----------
2 files changed, 49 insertions(+), 42 deletions(-)
diff --git a/src/targeting.js b/src/targeting.js
index dcd59f362c6..30407994b8e 100644
--- a/src/targeting.js
+++ b/src/targeting.js
@@ -35,20 +35,11 @@ export function getHighestCpmBidsFromBidPool(bidsReceived, highestCpmCallback) {
// filter top bid for each bucket by bidder
Object.keys(buckets).forEach(bucketKey => {
let bidsByBidder = groupBy(buckets[bucketKey], 'bidderCode');
- Object.keys(bidsByBidder).forEach(key => bids.push(bidsByBidder[key].reduce(highestCpmCallback, getEmptyBid())));
+ Object.keys(bidsByBidder).forEach(key => bids.push(bidsByBidder[key].reduce(highestCpmCallback)));
});
return bids;
}
-function getEmptyBid(adUnitCode) {
- return {
- adUnitCode: adUnitCode,
- cpm: 0,
- adserverTargeting: {},
- timeToRespond: 0
- };
-}
-
/**
* @typedef {Object.} targeting
* @property {string} targeting_key
@@ -222,7 +213,7 @@ export function newTargeting(auctionManager) {
.filter(uniques)
.map(adUnitCode => bidsReceived
.filter(bid => bid.adUnitCode === adUnitCode ? bid : null)
- .reduce(getHighestCpm, getEmptyBid(adUnitCode)));
+ .reduce(getHighestCpm));
};
/**
diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js
index 9910645be09..427ceeca74c 100644
--- a/test/spec/unit/core/targeting_spec.js
+++ b/test/spec/unit/core/targeting_spec.js
@@ -99,42 +99,68 @@ const bid3 = {
};
describe('targeting tests', function () {
+ let sandbox;
+ let enableSendAllBids = false;
+
+ beforeEach(function() {
+ sandbox = sinon.sandbox.create();
+
+ let origGetConfig = config.getConfig;
+ sandbox.stub(config, 'getConfig').callsFake(function (key) {
+ if (key === 'enableSendAllBids') {
+ return enableSendAllBids;
+ }
+ return origGetConfig.apply(config, arguments);
+ });
+ });
+
+ afterEach(function () {
+ sandbox.restore();
+ });
+
describe('getAllTargeting', function () {
let amBidsReceivedStub;
let amGetAdUnitsStub;
let bidExpiryStub;
+ let bidsReceived;
beforeEach(function () {
- $$PREBID_GLOBAL$$._sendAllBids = false;
- amBidsReceivedStub = sinon.stub(auctionManager, 'getBidsReceived').callsFake(function() {
- return [bid1, bid2, bid3];
+ bidsReceived = [bid1, bid2, bid3];
+
+ amBidsReceivedStub = sandbox.stub(auctionManager, 'getBidsReceived').callsFake(function() {
+ return bidsReceived;
});
- amGetAdUnitsStub = sinon.stub(auctionManager, 'getAdUnitCodes').callsFake(function() {
+ amGetAdUnitsStub = sandbox.stub(auctionManager, 'getAdUnitCodes').callsFake(function() {
return ['/123456/header-bid-tag-0'];
});
- bidExpiryStub = sinon.stub(targetingModule, 'isBidNotExpired').returns(true);
- });
-
- afterEach(function () {
- auctionManager.getBidsReceived.restore();
- auctionManager.getAdUnitCodes.restore();
- targetingModule.isBidNotExpired.restore();
+ bidExpiryStub = sandbox.stub(targetingModule, 'isBidNotExpired').returns(true);
});
describe('when hb_deal is present in bid.adserverTargeting', function () {
+ let bid4;
+
+ beforeEach(function() {
+ bid4 = utils.deepClone(bid1);
+ bid4.adserverTargeting['hb_bidder'] = bid4.bidder = bid4.bidderCode = 'appnexus';
+ bid4.cpm = 0;
+ enableSendAllBids = true;
+
+ bidsReceived.push(bid4);
+ });
+
it('returns targeting with both hb_deal and hb_deal_{bidder_code}', function () {
const targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']);
// We should add both keys rather than one or the other
- expect(targeting['/123456/header-bid-tag-0']).to.contain.keys('hb_deal', `hb_deal_${bid1.bidderCode}`);
+ expect(targeting['/123456/header-bid-tag-0']).to.contain.keys('hb_deal', `hb_deal_${bid1.bidderCode}`, `hb_deal_${bid4.bidderCode}`);
// We should assign both keys the same value
expect(targeting['/123456/header-bid-tag-0']['hb_deal']).to.deep.equal(targeting['/123456/header-bid-tag-0'][`hb_deal_${bid1.bidderCode}`]);
});
});
- it('selects the top bid when _sendAllBids true', function () {
- config.setConfig({ enableSendAllBids: true });
+ it('selects the top bid when enableSendAllBids true', function () {
+ enableSendAllBids = true;
let targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']);
// we should only get the targeting data for the one requested adunit
@@ -155,14 +181,13 @@ describe('targeting tests', function () {
let bidExpiryStub;
beforeEach(function () {
- $$PREBID_GLOBAL$$._sendAllBids = false;
- amBidsReceivedStub = sinon.stub(auctionManager, 'getBidsReceived').callsFake(function() {
+ amBidsReceivedStub = sandbox.stub(auctionManager, 'getBidsReceived').callsFake(function() {
return [];
});
- amGetAdUnitsStub = sinon.stub(auctionManager, 'getAdUnitCodes').callsFake(function() {
+ amGetAdUnitsStub = sandbox.stub(auctionManager, 'getAdUnitCodes').callsFake(function() {
return ['/123456/header-bid-tag-0'];
});
- bidExpiryStub = sinon.stub(targetingModule, 'isBidNotExpired').returns(true);
+ bidExpiryStub = sandbox.stub(targetingModule, 'isBidNotExpired').returns(true);
});
afterEach(function () {
@@ -184,13 +209,8 @@ describe('targeting tests', function () {
let bidExpiryStub;
let auctionManagerStub;
beforeEach(function () {
- bidExpiryStub = sinon.stub(targetingModule, 'isBidNotExpired').returns(true);
- auctionManagerStub = sinon.stub(auctionManager, 'getBidsReceived');
- });
-
- afterEach(function () {
- bidExpiryStub.restore();
- auctionManagerStub.restore();
+ bidExpiryStub = sandbox.stub(targetingModule, 'isBidNotExpired').returns(true);
+ auctionManagerStub = sandbox.stub(auctionManager, 'getBidsReceived');
});
it('should use bids from pool to get Winning Bid', function () {
@@ -248,14 +268,10 @@ describe('targeting tests', function () {
let auctionManagerStub;
let timestampStub;
beforeEach(function () {
- auctionManagerStub = sinon.stub(auctionManager, 'getBidsReceived');
- timestampStub = sinon.stub(utils, 'timestamp');
+ auctionManagerStub = sandbox.stub(auctionManager, 'getBidsReceived');
+ timestampStub = sandbox.stub(utils, 'timestamp');
});
- afterEach(function () {
- auctionManagerStub.restore();
- timestampStub.restore();
- });
it('should not include expired bids in the auction', function () {
timestampStub.returns(200000);
// Pool is having 4 bids from 2 auctions. All the bids are expired and only bid #3 is passing the bidExpiry check.
From d25f57187b8eeae25a7aa5f3a26ffa76ea4e865b Mon Sep 17 00:00:00 2001
From: kusapan
Date: Thu, 1 Nov 2018 23:23:40 +0900
Subject: [PATCH 18/62] YIELDONE adapter - support Video (#3227)
* added UserSync
* added UserSync Unit Test
* support for multi sizes
* register the adapter as supporting video
* supporting video
* change requestId acquisition method
* fix the parameter name of dealID
* update test parameters
* support instream video
* add test for bidRequest
* add test for interpretResponse
* add test params
* add note to documentaion
* clarifying the multi-format support message
---
modules/yieldoneBidAdapter.js | 36 ++++--
modules/yieldoneBidAdapter.md | 50 ++++++--
test/spec/modules/yieldoneBidAdapter_spec.js | 117 ++++++++++++++-----
3 files changed, 154 insertions(+), 49 deletions(-)
diff --git a/modules/yieldoneBidAdapter.js b/modules/yieldoneBidAdapter.js
index cdcab0c705a..5843ce9d339 100644
--- a/modules/yieldoneBidAdapter.js
+++ b/modules/yieldoneBidAdapter.js
@@ -1,6 +1,7 @@
import * as utils from 'src/utils';
import {config} from 'src/config';
import {registerBidder} from 'src/adapters/bidderFactory';
+import { BANNER, VIDEO } from 'src/mediaTypes';
const BIDDER_CODE = 'yieldone';
const ENDPOINT_URL = '//y.one.impact-ad.jp/h_bid';
@@ -9,15 +10,13 @@ const USER_SYNC_URL = '//y.one.impact-ad.jp/push_sync';
export const spec = {
code: BIDDER_CODE,
aliases: ['y1'],
+ supportedMediaTypes: [BANNER, VIDEO],
isBidRequestValid: function(bid) {
return !!(bid.params.placementId);
},
buildRequests: function(validBidRequests) {
return validBidRequests.map(bidRequest => {
const params = bidRequest.params;
- const sizes = utils.parseSizesInput(bidRequest.sizes)[0];
- const width = sizes.split('x')[0];
- const height = sizes.split('x')[1];
const placementId = params.placementId;
const cb = Math.floor(Math.random() * 99999999999);
const referrer = encodeURIComponent(utils.getTopWindowUrl());
@@ -25,13 +24,24 @@ export const spec = {
const payload = {
v: 'hb1',
p: placementId,
- w: width,
- h: height,
cb: cb,
r: referrer,
uid: bidId,
t: 'i'
};
+
+ const videoMediaType = utils.deepAccess(bidRequest, 'mediaTypes.video');
+ if (bidRequest.mediaType === VIDEO || videoMediaType) {
+ const sizes = utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize') || bidRequest.sizes;
+ const size = utils.parseSizesInput(sizes)[0];
+ payload.w = size.split('x')[0];
+ payload.h = size.split('x')[1];
+ } else if ((utils.isEmpty(bidRequest.mediaType) && utils.isEmpty(bidRequest.mediaTypes)) ||
+ (bidRequest.mediaType === BANNER || (bidRequest.mediaTypes && bidRequest.mediaTypes[BANNER]))) {
+ const sizes = utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes') || bidRequest.sizes;
+ payload.sz = utils.parseSizesInput(sizes).join(',');
+ }
+
return {
method: 'GET',
url: ENDPOINT_URL,
@@ -47,12 +57,12 @@ export const spec = {
const height = response.height || 0;
const cpm = response.cpm * 1000 || 0;
if (width !== 0 && height !== 0 && cpm !== 0 && crid !== 0) {
- const dealId = response.dealid || '';
+ const dealId = response.dealId || '';
const currency = response.currency || 'JPY';
const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue;
const referrer = utils.getTopWindowUrl();
const bidResponse = {
- requestId: bidRequest.data.uid,
+ requestId: response.uid,
cpm: cpm,
width: response.width,
height: response.height,
@@ -61,9 +71,17 @@ export const spec = {
currency: currency,
netRevenue: netRevenue,
ttl: config.getConfig('_bidderTimeout'),
- referrer: referrer,
- ad: response.adTag
+ referrer: referrer
};
+
+ if (response.adTag) {
+ bidResponse.mediaType = BANNER;
+ bidResponse.ad = response.adTag;
+ } else if (response.adm) {
+ bidResponse.mediaType = VIDEO;
+ bidResponse.vastXml = response.adm;
+ }
+
bidResponses.push(bidResponse);
}
return bidResponses;
diff --git a/modules/yieldoneBidAdapter.md b/modules/yieldoneBidAdapter.md
index b154a2ee781..1414d4e464f 100644
--- a/modules/yieldoneBidAdapter.md
+++ b/modules/yieldoneBidAdapter.md
@@ -10,20 +10,46 @@ Maintainer: y1dev@platform-one.co.jp
Connect to YIELDONE for bids.
-THE YIELDONE adapter requires setup and approval from the YIELDONE team. Please reach out to your account team or y1s@platform-one.co.jp for more information.
+THE YIELDONE adapter requires setup and approval from the YIELDONE team.
+Please reach out to your account team or y1s@platform-one.co.jp for more information.
+
+Note: THE YIELDONE adapter do not support "multi-format" scenario... if both
+banner and video are specified as mediatypes, YIELDONE will treat it as a video unit.
# Test Parameters
-```
- var adUnits = [{
- code: 'banner-ad-div',
- sizes: [[300, 250]],
- bids: [{
- bidder: 'yieldone',
- params: {
- placementId: '44082'
- }
- }]
- }];
+```javascript
+var adUnits = [
+ // Banner adUnit
+ {
+ code: 'banner-div',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [336, 280]]
+ }
+ },
+ bids: [{
+ bidder: 'yieldone',
+ params: {
+ placementId: '36891'
+ }
+ }]
+ },
+ // Video adUnit
+ {
+ code: 'video-div',
+ mediaTypes: {
+ video: {
+ playerSize: [[640, 480]],
+ context: 'outstream'
+ },
+ },
+ bids: [{
+ bidder: 'yieldone',
+ params: {
+ placementId: '41993'
+ }
+ }]
+ }
```
### Configuration
diff --git a/test/spec/modules/yieldoneBidAdapter_spec.js b/test/spec/modules/yieldoneBidAdapter_spec.js
index b717ef52709..19756b86bc1 100644
--- a/test/spec/modules/yieldoneBidAdapter_spec.js
+++ b/test/spec/modules/yieldoneBidAdapter_spec.js
@@ -3,6 +3,7 @@ import { spec } from 'modules/yieldoneBidAdapter';
import { newBidder } from 'src/adapters/bidderFactory';
const ENDPOINT = '//y.one.impact-ad.jp/h_bid';
+const USER_SYNC_URL = '//y.one.impact-ad.jp/push_sync';
describe('yieldoneBidAdapter', function() {
const adapter = newBidder(spec);
@@ -11,12 +12,10 @@ describe('yieldoneBidAdapter', function() {
let bid = {
'bidder': 'yieldone',
'params': {
- placementId: '44082'
+ placementId: '36891'
},
'adUnitCode': 'adunit-code',
- 'sizes': [
- [300, 250]
- ],
+ 'sizes': [[300, 250], [336, 280]],
'bidId': '23beaa6af6cdde',
'bidderRequestId': '19c0c1efdf37e7',
'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1',
@@ -43,12 +42,10 @@ describe('yieldoneBidAdapter', function() {
{
'bidder': 'yieldone',
'params': {
- placementId: '44082'
+ placementId: '36891'
},
'adUnitCode': 'adunit-code1',
- 'sizes': [
- [300, 250]
- ],
+ 'sizes': [[300, 250], [336, 280]],
'bidId': '23beaa6af6cdde',
'bidderRequestId': '19c0c1efdf37e7',
'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1',
@@ -56,12 +53,10 @@ describe('yieldoneBidAdapter', function() {
{
'bidder': 'yieldone',
'params': {
- placementId: '44337'
+ placementId: '47919'
},
'adUnitCode': 'adunit-code2',
- 'sizes': [
- [300, 250]
- ],
+ 'sizes': [[300, 250]],
'bidId': '382091349b149f"',
'bidderRequestId': '"1f9c98192de251"',
'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1',
@@ -79,18 +74,31 @@ describe('yieldoneBidAdapter', function() {
expect(request[0].url).to.equal(ENDPOINT);
expect(request[1].url).to.equal(ENDPOINT);
});
+
+ it('parameter sz has more than one size on banner requests', function () {
+ expect(request[0].data.sz).to.equal('300x250,336x280');
+ expect(request[1].data.sz).to.equal('300x250');
+ });
+
+ it('width and height should be set as separate parameters on outstream requests', function () {
+ const bidRequest = Object.assign({}, bidRequests[0]);
+ bidRequest.mediaTypes = {};
+ bidRequest.mediaTypes.video = {context: 'outstream'};
+ const request = spec.buildRequests([bidRequest]);
+ expect(request[0].data.w).to.equal('300');
+ expect(request[0].data.h).to.equal('250');
+ });
});
describe('interpretResponse', function () {
- let bidRequest = [
+ let bidRequestBanner = [
{
'method': 'GET',
'url': '//y.one.impact-ad.jp/h_bid',
'data': {
'v': 'hb1',
- 'p': '44082',
- 'w': '300',
- 'h': '250',
+ 'p': '36891',
+ 'sz': '300x250,336x280',
'cb': 12892917383,
'r': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836',
'uid': '23beaa6af6cdde',
@@ -99,34 +107,89 @@ describe('yieldoneBidAdapter', function() {
}
];
- let serverResponse = {
+ let serverResponseBanner = {
body: {
'adTag': '',
+ 'uid': '23beaa6af6cdde',
+ 'height': 250,
+ 'width': 300,
'cpm': 0.0536616,
'crid': '2494768',
+ 'currency': 'JPY',
'statusMessage': 'Bid available',
- 'uid': '23beaa6af6cdde',
- 'width': 300,
- 'height': 250
+ 'dealId': 'P1-FIX-7800-DSP-MON'
}
};
- it('should get the correct bid response', function () {
+ it('should get the correct bid response for banner', function () {
let expectedResponse = [{
'requestId': '23beaa6af6cdde',
'cpm': 53.6616,
'width': 300,
'height': 250,
'creativeId': '2494768',
- 'dealId': '',
+ 'dealId': 'P1-FIX-7800-DSP-MON',
'currency': 'JPY',
'netRevenue': true,
'ttl': 3000,
'referrer': '',
+ 'mediaType': 'banner',
'ad': ''
}];
- let result = spec.interpretResponse(serverResponse, bidRequest[0]);
- expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse));
+ let result = spec.interpretResponse(serverResponseBanner, bidRequestBanner[0]);
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0]));
+ expect(result[0].mediaType).to.equal(expectedResponse[0].mediaType);
+ });
+
+ let serverResponseVideo = {
+ body: {
+ 'uid': '23beaa6af6cdde',
+ 'height': 360,
+ 'width': 640,
+ 'cpm': 0.0536616,
+ 'dealId': 'P1-FIX-766-DSP-MON',
+ 'crid': '2494768',
+ 'currency': 'JPY',
+ 'statusMessage': 'Bid available',
+ 'adm': ''
+ }
+ };
+
+ let bidRequestVideo = [
+ {
+ 'method': 'GET',
+ 'url': '//y.one.impact-ad.jp/h_bid',
+ 'data': {
+ 'v': 'hb1',
+ 'p': '41993',
+ 'w': '640',
+ 'h': '360',
+ 'cb': 12892917383,
+ 'r': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836',
+ 'uid': '23beaa6af6cdde',
+ 't': 'i'
+ }
+ }
+ ];
+
+ it('should get the correct bid response for video', function () {
+ let expectedResponse = [{
+ 'requestId': '23beaa6af6cdde',
+ 'cpm': 53.6616,
+ 'width': 640,
+ 'height': 360,
+ 'creativeId': '2494768',
+ 'dealId': 'P1-FIX-7800-DSP-MON',
+ 'currency': 'JPY',
+ 'netRevenue': true,
+ 'ttl': 3000,
+ 'referrer': '',
+ 'mediaType': 'video',
+ 'vastXml': ''
+ }];
+ let result = spec.interpretResponse(serverResponseVideo, bidRequestVideo[0]);
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0]));
+ expect(result[0].mediaType).to.equal(expectedResponse[0].mediaType);
});
it('handles empty bid response', function () {
@@ -140,14 +203,12 @@ describe('yieldoneBidAdapter', function() {
'cpm': 0
}
};
- let result = spec.interpretResponse(response, bidRequest[0]);
+ let result = spec.interpretResponse(response, bidRequestBanner[0]);
expect(result.length).to.equal(0);
});
});
describe('getUserSyncs', function () {
- const userSyncUrl = '//y.one.impact-ad.jp/push_sync';
-
it('handles empty sync options', function () {
expect(spec.getUserSyncs({})).to.be.empty;
});
@@ -156,7 +217,7 @@ describe('yieldoneBidAdapter', function() {
expect(spec.getUserSyncs({
'iframeEnabled': true
})).to.deep.equal([{
- type: 'iframe', url: userSyncUrl
+ type: 'iframe', url: USER_SYNC_URL
}]);
});
});
From d854db39c0d6b70f4369a634089129b6baecdf17 Mon Sep 17 00:00:00 2001
From: Kamoris
Date: Thu, 1 Nov 2018 15:29:51 +0100
Subject: [PATCH 19/62] rtbhouseBidAdapter changes (#3241)
* Add transactionId support
* Change site getting method
* Add bidfloor param
---
modules/rtbhouseBidAdapter.js | 21 +++++--
modules/rtbhouseBidAdapter.md | 6 +-
test/spec/modules/rtbhouseBidAdapter_spec.js | 63 +++++++++++++++-----
3 files changed, 69 insertions(+), 21 deletions(-)
diff --git a/modules/rtbhouseBidAdapter.js b/modules/rtbhouseBidAdapter.js
index e4a30782dbe..0be3887637d 100644
--- a/modules/rtbhouseBidAdapter.js
+++ b/modules/rtbhouseBidAdapter.js
@@ -43,9 +43,12 @@ export const spec = {
const request = {
id: validBidRequests[0].auctionId,
imp: validBidRequests.map(slot => mapImpression(slot)),
- site: mapSite(validBidRequests),
+ site: mapSite(validBidRequests, bidderRequest),
cur: DEFAULT_CURRENCY_ARR,
- test: validBidRequests[0].params.test || 0
+ test: validBidRequests[0].params.test || 0,
+ source: {
+ tid: validBidRequests[0].transactionId
+ }
};
if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) {
const consentStr = (bidderRequest.gdprConsent.consentString)
@@ -89,12 +92,19 @@ registerBidder(spec);
* @returns {object} Imp by OpenRTB 2.5 §3.2.4
*/
function mapImpression(slot) {
- return {
+ const imp = {
id: slot.bidId,
banner: mapBanner(slot),
native: mapNative(slot),
tagid: slot.adUnitCode.toString()
};
+
+ const bidfloor = parseFloat(slot.params.bidfloor);
+ if (bidfloor) {
+ imp.bidfloor = bidfloor
+ }
+
+ return imp;
}
/**
@@ -118,9 +128,10 @@ function mapBanner(slot) {
/**
* @param {object} slot Ad Unit Params by Prebid
+ * @param {object} bidderRequest by Prebid
* @returns {object} Site by OpenRTB 2.5 §3.2.13
*/
-function mapSite(slot) {
+function mapSite(slot, bidderRequest) {
const pubId = slot && slot.length > 0
? slot[0].params.publisherId
: 'unknown';
@@ -128,7 +139,7 @@ function mapSite(slot) {
publisher: {
id: pubId.toString(),
},
- page: utils.getTopWindowUrl(),
+ page: bidderRequest.refererInfo.referer,
name: utils.getOrigin()
}
}
diff --git a/modules/rtbhouseBidAdapter.md b/modules/rtbhouseBidAdapter.md
index a2d7e2aedda..c847e688941 100644
--- a/modules/rtbhouseBidAdapter.md
+++ b/modules/rtbhouseBidAdapter.md
@@ -7,7 +7,7 @@ Maintainer: prebid@rtbhouse.com
# Description
Connects to RTB House unique demand.
-Banner formats are supported.
+Banner and native formats are supported.
Unique publisherId is required.
Please reach out to pmp@rtbhouse.com to receive your own
@@ -23,7 +23,8 @@ Please reach out to pmp@rtbhouse.com to receive your own
bidder: "rtbhouse",
params: {
region: 'prebid-eu',
- publisherId: 'PREBID_TEST_ID'
+ publisherId: 'PREBID_TEST_ID',
+ bidfloor: 0.01 // optional
}
}
]
@@ -50,6 +51,7 @@ Please reach out to pmp@rtbhouse.com to receive your own
params: {
region: 'prebid-eu',
publisherId: 'PREBID_TEST_ID'
+ bidfloor: 0.01 // optional
}
}
]
diff --git a/test/spec/modules/rtbhouseBidAdapter_spec.js b/test/spec/modules/rtbhouseBidAdapter_spec.js
index 3c1d81a86c9..bd341465ab9 100644
--- a/test/spec/modules/rtbhouseBidAdapter_spec.js
+++ b/test/spec/modules/rtbhouseBidAdapter_spec.js
@@ -52,17 +52,26 @@ describe('RTBHouseAdapter', () => {
'sizes': [[300, 250], [300, 600]],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
- 'auctionId': '1d1a030790a475'
+ 'auctionId': '1d1a030790a475',
+ 'transactionId': 'example-transaction-id',
}
];
+ const bidderRequest = {
+ 'refererInfo': {
+ 'numIframes': 0,
+ 'reachedTop': true,
+ 'referer': 'http://example.com',
+ 'stack': ['http://example.com']
+ }
+ };
it('should build test param into the request', () => {
- let builtTestRequest = spec.buildRequests(bidRequests).data;
+ let builtTestRequest = spec.buildRequests(bidRequests, bidderRequest).data;
expect(JSON.parse(builtTestRequest).test).to.equal(1);
});
it('should build valid OpenRTB banner object', () => {
- const request = JSON.parse(spec.buildRequests((bidRequests)).data);
+ const request = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data);
const imp = request.imp[0];
expect(imp.banner).to.deep.equal({
w: 300,
@@ -80,7 +89,7 @@ describe('RTBHouseAdapter', () => {
it('sends bid request to ENDPOINT via POST', function () {
let bidRequest = Object.assign([], bidRequests);
delete bidRequest[0].params.test;
- const request = spec.buildRequests(bidRequest);
+ const request = spec.buildRequests(bidRequest, bidderRequest);
expect(request.url).to.equal('https://prebid-eu.creativecdn.com/bidder/prebid/bids');
expect(request.method).to.equal('POST');
});
@@ -88,7 +97,7 @@ describe('RTBHouseAdapter', () => {
it('should not populate GDPR if for non-EEA users', function () {
let bidRequest = Object.assign([], bidRequests);
delete bidRequest[0].params.test;
- const request = spec.buildRequests(bidRequest);
+ const request = spec.buildRequests(bidRequest, bidderRequest);
let data = JSON.parse(request.data);
expect(data).to.not.have.property('regs');
expect(data).to.not.have.property('user');
@@ -97,12 +106,15 @@ describe('RTBHouseAdapter', () => {
it('should populate GDPR and consent string if available for EEA users', function () {
let bidRequest = Object.assign([], bidRequests);
delete bidRequest[0].params.test;
- const request = spec.buildRequests(bidRequest, {
- gdprConsent: {
- gdprApplies: true,
- consentString: 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='
- }
- });
+ const request = spec.buildRequests(
+ bidRequest,
+ Object.assign({}, bidderRequest, {
+ gdprConsent: {
+ gdprApplies: true,
+ consentString: 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='
+ }
+ })
+ );
let data = JSON.parse(request.data);
expect(data.regs.ext.gdpr).to.equal(1);
expect(data.user.ext.consent).to.equal('BOJ8RZsOJ8RZsABAB8AAAAAZ-A');
@@ -111,7 +123,14 @@ describe('RTBHouseAdapter', () => {
it('should populate GDPR and empty consent string if available for EEA users without consent string but with consent', function () {
let bidRequest = Object.assign([], bidRequests);
delete bidRequest[0].params.test;
- const request = spec.buildRequests(bidRequest, {gdprConsent: {gdprApplies: true}});
+ const request = spec.buildRequests(
+ bidRequest,
+ Object.assign({}, bidderRequest, {
+ gdprConsent: {
+ gdprApplies: true
+ }
+ })
+ );
let data = JSON.parse(request.data);
expect(data.regs.ext.gdpr).to.equal(1);
expect(data.user.ext.consent).to.equal('');
@@ -119,11 +138,26 @@ describe('RTBHouseAdapter', () => {
it('should include banner imp in request', () => {
const bidRequest = Object.assign([], bidRequests);
- const request = spec.buildRequests(bidRequest);
+ const request = spec.buildRequests(bidRequest, bidderRequest);
const data = JSON.parse(request.data);
expect(data.imp[0].banner).to.not.be.empty;
});
+ it('should include source.tid in request', () => {
+ const bidRequest = Object.assign([], bidRequests);
+ const request = spec.buildRequests(bidRequest, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.source.tid).to.equal('example-transaction-id');
+ });
+
+ it('should include bidfloor in request if available', () => {
+ const bidRequest = Object.assign([], bidRequests);
+ bidRequest[0].params.bidfloor = 0.01;
+ const request = spec.buildRequests(bidRequest, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.imp[0].bidfloor).to.equal(0.01)
+ });
+
describe('native imp', () => {
function basicRequest(extension) {
return Object.assign({
@@ -139,7 +173,8 @@ describe('RTBHouseAdapter', () => {
}
function buildImp(request) {
- return JSON.parse(spec.buildRequests([request]).data).imp[0];
+ const resultRequest = spec.buildRequests([request], bidderRequest);
+ return JSON.parse(resultRequest.data).imp[0];
}
it('should extract native params when single mediaType', () => {
From ec023bae07fef725c8a69f8dc111f227138d0c88 Mon Sep 17 00:00:00 2001
From: ankur-modi <38654685+ankur-modi@users.noreply.github.com>
Date: Thu, 1 Nov 2018 22:56:02 +0530
Subject: [PATCH 20/62] correct user agent value population (#3248)
---
modules/oneVideoBidAdapter.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/modules/oneVideoBidAdapter.js b/modules/oneVideoBidAdapter.js
index 5b1fd999ee6..bd341dfd79f 100644
--- a/modules/oneVideoBidAdapter.js
+++ b/modules/oneVideoBidAdapter.js
@@ -136,7 +136,6 @@ function isConsentRequired(consentData) {
function getRequestData(bid, consentData) {
let loc = utils.getTopWindowLocation();
- let global = (window.top) ? window.top : window;
let page = (bid.params.site && bid.params.site.page) ? (bid.params.site.page) : (loc.href);
let ref = (bid.params.site && bid.params.site.referrer) ? bid.params.site.referrer : utils.getTopWindowReferrer();
let bidData = {
@@ -160,7 +159,7 @@ function getRequestData(bid, consentData) {
ref: ref
},
device: {
- ua: global.navigator.userAgent
+ ua: navigator.userAgent
},
tmax: 200
};
From ae42588244550b2c44848d5d65d7fa5a89355c3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?=
Date: Mon, 14 May 2018 10:20:27 +0000
Subject: [PATCH 21/62] RVR-1124 Setup initial skeleton analytics adapter that
can send something.
Approved-by: Alessandro Di Giovanni
---
modules/rivrAnalyticsAdapter.js | 188 ++++++++++++++++++++++++++++++++
1 file changed, 188 insertions(+)
create mode 100644 modules/rivrAnalyticsAdapter.js
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
new file mode 100644
index 00000000000..37d00938c18
--- /dev/null
+++ b/modules/rivrAnalyticsAdapter.js
@@ -0,0 +1,188 @@
+import {ajax} from 'src/ajax';
+import adapter from 'src/AnalyticsAdapter';
+import CONSTANTS from 'src/constants.json';
+import adaptermanager from 'src/adaptermanager';
+import { logInfo } from 'src/utils';
+
+const analyticsType = 'endpoint';
+const DEFAULT_HOST = 'integrations.rivr.simplaex.net/prebid/auctions';
+const DEFAULT_QUEUE_TIMEOUT = 4000;
+
+const RIVR_HB_EVENTS = {
+ AUCTION_INIT: 'auctionInit',
+ BID_REQUEST: 'bidRequested',
+ BID_RESPONSE: 'bidResponse',
+ BID_WON: 'bidWon',
+ AUCTION_END: 'auctionEnd',
+ TIMEOUT: 'adapterTimedOut'
+};
+
+let rivrAnalytics = Object.assign(adapter({analyticsType}), {
+ track({ eventType, args }) {
+ if (!rivrAnalytics.context) {
+ return;
+ }
+ logInfo(`ARGUMENTS FOR TYPE: ============= ${eventType}`, args);
+ let handler = null;
+ switch (eventType) {
+ case CONSTANTS.EVENTS.AUCTION_INIT:
+ if (rivrAnalytics.context.queue) {
+ rivrAnalytics.context.queue.init();
+ }
+ handler = trackAuctionInit;
+ break;
+ case CONSTANTS.EVENTS.BID_REQUESTED:
+ handler = trackBidRequest;
+ break;
+ case CONSTANTS.EVENTS.BID_RESPONSE:
+ handler = trackBidResponse;
+ break;
+ case CONSTANTS.EVENTS.BID_WON:
+ handler = trackBidWon;
+ break;
+ case CONSTANTS.EVENTS.BID_TIMEOUT:
+ handler = trackBidTimeout;
+ break;
+ case CONSTANTS.EVENTS.AUCTION_END:
+ handler = trackAuctionEnd;
+ break;
+ }
+ if (handler) {
+ let events = handler(args);
+ if (rivrAnalytics.context.queue) {
+ rivrAnalytics.context.queue.push(events);
+ }
+ if (eventType === CONSTANTS.EVENTS.AUCTION_END) {
+ sendAll();
+ }
+ }
+ }
+});
+
+function sendAll() {
+ let events = rivrAnalytics.context.queue.popAll();
+ if (events.length !== 0) {
+ let req = Object.assign({}, {hb_ev: events});
+ logInfo('sending request to analytics => ', req);
+ ajax(`http://${rivrAnalytics.context.host}`, () => {
+ }, JSON.stringify(req));
+ }
+}
+
+function trackAuctionInit() {
+ rivrAnalytics.context.auctionTimeStart = Date.now();
+ const event = createHbEvent(undefined, RIVR_HB_EVENTS.AUCTION_INIT);
+ return [event];
+}
+
+function trackBidRequest(args) {
+ return args.bids.map(bid =>
+ createHbEvent(args.bidderCode, RIVR_HB_EVENTS.BID_REQUEST, bid.adUnitCode));
+}
+
+function trackBidResponse(args) {
+ const event = createHbEvent(args.bidderCode, RIVR_HB_EVENTS.BID_RESPONSE,
+ args.adUnitCode, args.cpm, args.timeToRespond / 1000);
+ return [event];
+}
+
+function trackBidWon(args) {
+ const event = createHbEvent(args.bidderCode, RIVR_HB_EVENTS.BID_WON, args.adUnitCode, args.cpm);
+ return [event];
+}
+
+function trackAuctionEnd(args) {
+ const event = createHbEvent(undefined, RIVR_HB_EVENTS.AUCTION_END, undefined,
+ undefined, (Date.now() - rivrAnalytics.context.auctionTimeStart) / 1000);
+ return [event];
+}
+
+function trackBidTimeout(args) {
+ return args.map(bidderName => createHbEvent(bidderName, RIVR_HB_EVENTS.TIMEOUT));
+}
+
+function createHbEvent(adapter, event, tagid = undefined, value = 0, time = 0) {
+ let ev = { event: event };
+ if (adapter) {
+ ev.adapter = adapter
+ }
+ if (tagid) {
+ ev.tagid = tagid;
+ }
+ if (value) {
+ ev.val = value;
+ }
+ if (time) {
+ ev.time = time;
+ }
+ return ev;
+}
+
+/**
+ * Expiring queue implementation. Fires callback on elapsed timeout since last last update or creation.
+ * @param callback
+ * @param ttl
+ * @constructor
+ */
+export function ExpiringQueue(callback, ttl) {
+ let queue = [];
+ let timeoutId;
+
+ this.push = (event) => {
+ if (event instanceof Array) {
+ queue.push.apply(queue, event);
+ } else {
+ queue.push(event);
+ }
+ reset();
+ };
+
+ this.popAll = () => {
+ let result = queue;
+ queue = [];
+ reset();
+ return result;
+ };
+
+ /**
+ * For test/debug purposes only
+ * @return {Array}
+ */
+ this.peekAll = () => {
+ return queue;
+ };
+
+ this.init = reset;
+
+ function reset() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ timeoutId = setTimeout(() => {
+ if (queue.length) {
+ callback();
+ }
+ }, ttl);
+ }
+}
+
+// save the base class function
+rivrAnalytics.originEnableAnalytics = rivrAnalytics.enableAnalytics;
+
+// override enableAnalytics so we can get access to the config passed in from the page
+rivrAnalytics.enableAnalytics = (config) => {
+ rivrAnalytics.context = {
+ host: config.options.host || DEFAULT_HOST,
+ pubId: config.options.pubId,
+ queue: new ExpiringQueue(sendAll, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
+ };
+ logInfo('Rivr Analytics enabled with config', rivrAnalytics.context);
+ rivrAnalytics.originEnableAnalytics(config);
+};
+
+adaptermanager.registerAnalyticsAdapter({
+ adapter: rivrAnalytics,
+ code: 'rivr'
+});
+
+export default rivrAnalytics
From 4aa0799f3f0f515423055e6f56cc927160ffcca6 Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Mon, 14 May 2018 14:17:24 +0200
Subject: [PATCH 22/62] Formatted auction/events data to fit needed schema.
---
modules/rivrAnalyticsAdapter.js | 208 ++++++++++++++++++++++++--------
1 file changed, 156 insertions(+), 52 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 37d00938c18..7a5dc266646 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -5,18 +5,9 @@ import adaptermanager from 'src/adaptermanager';
import { logInfo } from 'src/utils';
const analyticsType = 'endpoint';
-const DEFAULT_HOST = 'integrations.rivr.simplaex.net/prebid/auctions';
+const DEFAULT_HOST = 'integrations.rivr.simplaex.net/prebid';
const DEFAULT_QUEUE_TIMEOUT = 4000;
-const RIVR_HB_EVENTS = {
- AUCTION_INIT: 'auctionInit',
- BID_REQUEST: 'bidRequested',
- BID_RESPONSE: 'bidResponse',
- BID_WON: 'bidWon',
- AUCTION_END: 'auctionEnd',
- TIMEOUT: 'adapterTimedOut'
-};
-
let rivrAnalytics = Object.assign(adapter({analyticsType}), {
track({ eventType, args }) {
if (!rivrAnalytics.context) {
@@ -26,8 +17,8 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
let handler = null;
switch (eventType) {
case CONSTANTS.EVENTS.AUCTION_INIT:
- if (rivrAnalytics.context.queue) {
- rivrAnalytics.context.queue.init();
+ if (rivrAnalytics.context.impressionsQueue) {
+ rivrAnalytics.context.impressionsQueue.init();
}
handler = trackAuctionInit;
break;
@@ -48,83 +39,196 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
break;
}
if (handler) {
- let events = handler(args);
- if (rivrAnalytics.context.queue) {
- rivrAnalytics.context.queue.push(events);
- }
- if (eventType === CONSTANTS.EVENTS.AUCTION_END) {
- sendAll();
+ if (handler == trackBidWon) {
+ let impressions = handler(args);
+ if (rivrAnalytics.context.impressionsQueue) {
+ rivrAnalytics.context.impressionsQueue.push(impressions);
+ }
+ } else {
+ handler(args)
}
}
}
});
function sendAll() {
- let events = rivrAnalytics.context.queue.popAll();
- if (events.length !== 0) {
- let req = Object.assign({}, {hb_ev: events});
- logInfo('sending request to analytics => ', req);
- ajax(`http://${rivrAnalytics.context.host}`, () => {
- }, JSON.stringify(req));
+ let impressions = rivrAnalytics.context.impressionsQueue.popAll();
+ let auctionObject = rivrAnalytics.context.auctionObject
+ let req = Object.assign({}, {Auction: auctionObject});
+ auctionObject = createAuctionObject();
+ logInfo('sending request to analytics => ', req);
+ ajax(`http://${rivrAnalytics.context.host}/auctions`, () => {
+ }, JSON.stringify(req));
+
+ if (impressions.length !== 0) {
+ let impressionsReq = Object.assign({}, {impressions});
+ logInfo('sending impressions request to analytics => ', impressionsReq);
+ ajax(`http://${rivrAnalytics.context.host}/impressions`, () => {
+ }, JSON.stringify(impressionsReq));
}
}
-function trackAuctionInit() {
+function trackAuctionInit(args) {
rivrAnalytics.context.auctionTimeStart = Date.now();
- const event = createHbEvent(undefined, RIVR_HB_EVENTS.AUCTION_INIT);
- return [event];
+ rivrAnalytics.context.auctionObject.id = args.auctionId
}
function trackBidRequest(args) {
- return args.bids.map(bid =>
- createHbEvent(args.bidderCode, RIVR_HB_EVENTS.BID_REQUEST, bid.adUnitCode));
+ setCurrentUserId(args);
}
function trackBidResponse(args) {
- const event = createHbEvent(args.bidderCode, RIVR_HB_EVENTS.BID_RESPONSE,
- args.adUnitCode, args.cpm, args.timeToRespond / 1000);
- return [event];
+ let bidResponse = createBidResponse(args);
+ rivrAnalytics.context.auctionObject.bidResponses.push(bidResponse)
}
function trackBidWon(args) {
- const event = createHbEvent(args.bidderCode, RIVR_HB_EVENTS.BID_WON, args.adUnitCode, args.cpm);
- return [event];
+ let auctionObject = rivrAnalytics.context.auctionObject;
+ let bidResponse = createBidResponse(args)
+ let impression = createImpression(args)
+ let imp = createImp(args);
+ auctionObject.bidResponses.push(bidResponse)
+ auctionObject.imp.push(imp)
+
+ return [impression];
}
function trackAuctionEnd(args) {
- const event = createHbEvent(undefined, RIVR_HB_EVENTS.AUCTION_END, undefined,
- undefined, (Date.now() - rivrAnalytics.context.auctionTimeStart) / 1000);
- return [event];
+ rivrAnalytics.context.auctionTimeEnd = Date.now();
}
function trackBidTimeout(args) {
- return args.map(bidderName => createHbEvent(bidderName, RIVR_HB_EVENTS.TIMEOUT));
+ return [args]
}
-function createHbEvent(adapter, event, tagid = undefined, value = 0, time = 0) {
- let ev = { event: event };
- if (adapter) {
- ev.adapter = adapter
+function setCurrentUserId(bidRequested) {
+ let user = rivrAnalytics.context.auctionObject.user
+ if (!user.id) {
+ rivrAnalytics.context.pubId ? user.id = rivrAnalytics.context.pubId : user.id = bidRequested.bids[0].crumbs.pubcid
}
- if (tagid) {
- ev.tagid = tagid;
+}
+
+function createBidResponse(bidResponseEvent) {
+ return {
+ timestamp: bidResponseEvent.responseTimestamp,
+ status: bidResponseEvent.getStatusCode(),
+ total_duration: bidResponseEvent.timeToRespond,
+ bidderId: null,
+ bidder_name: bidResponseEvent.bidder,
+ cur: bidResponseEvent.currency,
+ seatid: [
+ {
+ seat: null,
+ bid: [
+ {
+ status: bidResponseEvent.getStatusCode(),
+ clear_price: bidResponseEvent.cpm,
+ attr: [],
+ crid: bidResponseEvent.creativeId,
+ cid: null,
+ id: null,
+ adid: bidResponseEvent.adId,
+ adomain: [],
+ iurl: null
+ }
+ ]
+ }
+ ]
}
- if (value) {
- ev.val = value;
+}
+
+function createImpression(bidWonEvent) {
+ return {
+ timestamp: bidWonEvent.responseTimestamp,
+ requestId: bidWonEvent.auctionId,
+ chargePrice: bidWonEvent.adserverTargeting.hb_pb,
+ publisherRevenue: bidWonEvent.cpm
}
- if (time) {
- ev.time = time;
+}
+
+function createImp(bidWonEvent) {
+ return {
+ tagid: bidWonEvent.adUnitCode,
+ displaymanager: null,
+ displaymanagerver: null,
+ secure: null,
+ bidfloor: null,
+ banner: {
+ w: bidWonEvent.width,
+ h: bidWonEvent.height,
+ pos: null,
+ expandable: [],
+ api: []
+ }
}
- return ev;
}
+function createAuctionObject() {
+ return {
+ id: null,
+ timestamp: null,
+ at: null,
+ bcat: [],
+ imp: [],
+ app: {
+ id: null,
+ name: null,
+ domain: null,
+ bundle: null,
+ cat: [],
+ publisher: {
+ id: null,
+ name: null
+ }
+ },
+ site: {
+ id: null,
+ name: null,
+ domain: null,
+ cat: [],
+ publisher: {
+ id: null,
+ name: null
+ }
+ },
+ device: {
+ geo: {
+ city: null,
+ country: null,
+ region: null,
+ zip: null,
+ type: null,
+ metro: null
+ },
+ connectiontype: null,
+ devicetype: null,
+ osv: null,
+ os: null,
+ model: null,
+ make: null,
+ carrier: null,
+ ip: null,
+ didsha1: null,
+ dpidmd5: null,
+ ext: {
+ uid: null
+ }
+ },
+ user: {
+ id: null,
+ yob: null,
+ gender: null,
+ },
+ bidResponses: []
+ }
+}
/**
* Expiring queue implementation. Fires callback on elapsed timeout since last last update or creation.
* @param callback
* @param ttl
* @constructor
*/
-export function ExpiringQueue(callback, ttl) {
+export function ExpiringQueue(callback, ttl, log) {
let queue = [];
let timeoutId;
@@ -143,7 +247,6 @@ export function ExpiringQueue(callback, ttl) {
reset();
return result;
};
-
/**
* For test/debug purposes only
* @return {Array}
@@ -174,7 +277,8 @@ rivrAnalytics.enableAnalytics = (config) => {
rivrAnalytics.context = {
host: config.options.host || DEFAULT_HOST,
pubId: config.options.pubId,
- queue: new ExpiringQueue(sendAll, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
+ auctionObject: createAuctionObject(),
+ impressionsQueue: new ExpiringQueue(sendAll, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
logInfo('Rivr Analytics enabled with config', rivrAnalytics.context);
rivrAnalytics.originEnableAnalytics(config);
From 08a438fdf4ec6d0d03d2ce852d98272c9c9ea002 Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Thu, 17 May 2018 15:40:33 +0200
Subject: [PATCH 23/62] Applied feedback.
---
modules/rivrAnalyticsAdapter.js | 56 +++++++++++++++++++--------------
1 file changed, 32 insertions(+), 24 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 7a5dc266646..d8a12c53707 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -66,47 +66,55 @@ function sendAll() {
ajax(`http://${rivrAnalytics.context.host}/impressions`, () => {
}, JSON.stringify(impressionsReq));
}
-}
+};
function trackAuctionInit(args) {
rivrAnalytics.context.auctionTimeStart = Date.now();
- rivrAnalytics.context.auctionObject.id = args.auctionId
-}
+ rivrAnalytics.context.auctionObject.id = args.auctionId;
+};
function trackBidRequest(args) {
- setCurrentUserId(args);
-}
+ setCurrentPublisherId(args);
+};
function trackBidResponse(args) {
let bidResponse = createBidResponse(args);
- rivrAnalytics.context.auctionObject.bidResponses.push(bidResponse)
-}
+ rivrAnalytics.context.auctionObject.bidResponses.push(bidResponse);
+};
function trackBidWon(args) {
let auctionObject = rivrAnalytics.context.auctionObject;
- let bidResponse = createBidResponse(args)
- let impression = createImpression(args)
+ let bidResponse = createBidResponse(args);
+ let impression = createImpression(args);
let imp = createImp(args);
- auctionObject.bidResponses.push(bidResponse)
- auctionObject.imp.push(imp)
+ auctionObject.bidResponses.push(bidResponse);
+ auctionObject.imp.push(imp);
return [impression];
}
function trackAuctionEnd(args) {
rivrAnalytics.context.auctionTimeEnd = Date.now();
-}
+};
function trackBidTimeout(args) {
- return [args]
-}
+ return [args];
+};
-function setCurrentUserId(bidRequested) {
- let user = rivrAnalytics.context.auctionObject.user
- if (!user.id) {
- rivrAnalytics.context.pubId ? user.id = rivrAnalytics.context.pubId : user.id = bidRequested.bids[0].crumbs.pubcid
+function setCurrentPublisherId(bidRequested) {
+ let site = rivrAnalytics.context.auctionObject.site;
+ let app = rivrAnalytics.context.auctionObject.app;
+ let pubId = rivrAnalytics.context.pubId;
+ if (!site.publisher.id || app.publisher.id) {
+ if (pubId) {
+ site.publisher.id = pubId;
+ app.publisher.id = pubId;
+ } else {
+ site.publisher.id = bidRequested.bids[0].crumbs.pubcid;
+ app.publisher.id = bidRequested.bids[0].crumbs.pubcid;
+ }
}
-}
+};
function createBidResponse(bidResponseEvent) {
return {
@@ -135,7 +143,7 @@ function createBidResponse(bidResponseEvent) {
}
]
}
-}
+};
function createImpression(bidWonEvent) {
return {
@@ -144,7 +152,7 @@ function createImpression(bidWonEvent) {
chargePrice: bidWonEvent.adserverTargeting.hb_pb,
publisherRevenue: bidWonEvent.cpm
}
-}
+};
function createImp(bidWonEvent) {
return {
@@ -161,7 +169,7 @@ function createImp(bidWonEvent) {
api: []
}
}
-}
+};
function createAuctionObject() {
return {
@@ -221,7 +229,7 @@ function createAuctionObject() {
},
bidResponses: []
}
-}
+};
/**
* Expiring queue implementation. Fires callback on elapsed timeout since last last update or creation.
* @param callback
@@ -267,7 +275,7 @@ export function ExpiringQueue(callback, ttl, log) {
}
}, ttl);
}
-}
+};
// save the base class function
rivrAnalytics.originEnableAnalytics = rivrAnalytics.enableAnalytics;
From 8bea7bc1bffe01885cd61dc2e3643f9dd2240c6b Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Wed, 16 May 2018 13:35:28 +0200
Subject: [PATCH 24/62] RVR-1135 fetched device data.
---
modules/rivrAnalyticsAdapter.js | 37 +++++++++++++++++++++++++++------
1 file changed, 31 insertions(+), 6 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index d8a12c53707..b6157a3d758 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -20,6 +20,10 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
if (rivrAnalytics.context.impressionsQueue) {
rivrAnalytics.context.impressionsQueue.init();
}
+ if (rivrAnalytics.context.auctionObject) {
+ rivrAnalytics.context.auctionObject = fulfillAuctionObject();
+ fetchLocalization();
+ }
handler = trackAuctionInit;
break;
case CONSTANTS.EVENTS.BID_REQUESTED:
@@ -55,7 +59,7 @@ function sendAll() {
let impressions = rivrAnalytics.context.impressionsQueue.popAll();
let auctionObject = rivrAnalytics.context.auctionObject
let req = Object.assign({}, {Auction: auctionObject});
- auctionObject = createAuctionObject();
+ auctionObject = fulfillAuctionObject();
logInfo('sending request to analytics => ', req);
ajax(`http://${rivrAnalytics.context.host}/auctions`, () => {
}, JSON.stringify(req));
@@ -116,6 +120,27 @@ function setCurrentPublisherId(bidRequested) {
}
};
+function fetchLocalization() {
+ ajax(`https://ipapi.co/json`, (rawLocalization) => {
+ let deviceLocation = rivrAnalytics.context.auctionObject.device.geo
+ let location = JSON.parse(rawLocalization)
+ deviceLocation.city = location.city;
+ deviceLocation.country = location.country
+ deviceLocation.region = location.region
+ deviceLocation.zip = location.postal
+ });
+};
+
+function getPlatformType() {
+ if (navigator.userAgent.match(/mobile/i)) {
+ return 'Mobile';
+ } else if (navigator.userAgent.match(/iPad|Android|Touch/i)) {
+ return 'Tablet';
+ } else {
+ return 'Desktop';
+ }
+}
+
function createBidResponse(bidResponseEvent) {
return {
timestamp: bidResponseEvent.responseTimestamp,
@@ -171,7 +196,7 @@ function createImp(bidWonEvent) {
}
};
-function createAuctionObject() {
+function fulfillAuctionObject() {
return {
id: null,
timestamp: null,
@@ -192,7 +217,7 @@ function createAuctionObject() {
site: {
id: null,
name: null,
- domain: null,
+ domain: window.location.hostname,
cat: [],
publisher: {
id: null,
@@ -208,8 +233,8 @@ function createAuctionObject() {
type: null,
metro: null
},
- connectiontype: null,
- devicetype: null,
+ connectiontype: navigator.connection.effectiveType,
+ devicetype: getPlatformType(),
osv: null,
os: null,
model: null,
@@ -285,7 +310,7 @@ rivrAnalytics.enableAnalytics = (config) => {
rivrAnalytics.context = {
host: config.options.host || DEFAULT_HOST,
pubId: config.options.pubId,
- auctionObject: createAuctionObject(),
+ auctionObject: {},
impressionsQueue: new ExpiringQueue(sendAll, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
logInfo('Rivr Analytics enabled with config', rivrAnalytics.context);
From 316aaea96ea3eae0a3d6037391db918db3ede71e Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Thu, 17 May 2018 16:17:01 +0200
Subject: [PATCH 25/62] Applied feedback.
---
modules/rivrAnalyticsAdapter.js | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index b6157a3d758..34eeeed745d 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -57,7 +57,7 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
function sendAll() {
let impressions = rivrAnalytics.context.impressionsQueue.popAll();
- let auctionObject = rivrAnalytics.context.auctionObject
+ let auctionObject = rivrAnalytics.context.auctionObject;
let req = Object.assign({}, {Auction: auctionObject});
auctionObject = fulfillAuctionObject();
logInfo('sending request to analytics => ', req);
@@ -121,13 +121,10 @@ function setCurrentPublisherId(bidRequested) {
};
function fetchLocalization() {
- ajax(`https://ipapi.co/json`, (rawLocalization) => {
- let deviceLocation = rivrAnalytics.context.auctionObject.device.geo
- let location = JSON.parse(rawLocalization)
- deviceLocation.city = location.city;
- deviceLocation.country = location.country
- deviceLocation.region = location.region
- deviceLocation.zip = location.postal
+ navigator.geolocation.getCurrentPosition((position) => {
+ let deviceLocation = rivrAnalytics.context.auctionObject.device.geo;
+ deviceLocation.lat = position.coords.latitude;
+ deviceLocation.long = position.coords.longitude;
});
};
From 5ad40bdf7bb5c1a0eba325e9eb8fcfafa25ad8e5 Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Thu, 17 May 2018 21:01:54 +0200
Subject: [PATCH 26/62] Fetched core.
---
test/spec/unit/pbjs_api_spec.js | 254 ++++++++++++++++++++++++++++++++
1 file changed, 254 insertions(+)
diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js
index a03339c76b3..144cbb656db 100644
--- a/test/spec/unit/pbjs_api_spec.js
+++ b/test/spec/unit/pbjs_api_spec.js
@@ -763,6 +763,260 @@ describe('Unit: Prebid Module', function () {
});
});
+ describe('getAdserverTargeting with `mediaTypePriceGranularity` set for media type', function() {
+ let currentPriceBucket;
+ let auction;
+ let ajaxStub;
+ let response;
+ let cbTimeout = 3000;
+ let auctionManagerInstance;
+ let targeting;
+
+ const bannerResponse = {
+ 'version': '0.0.1',
+ 'tags': [{
+ 'uuid': '4d0a6829338a07',
+ 'tag_id': 4799418,
+ 'auction_id': '2256922143947979797',
+ 'no_ad_url': 'http://lax1-ib.adnxs.com/no-ad',
+ 'timeout_ms': 2500,
+ 'ads': [{
+ 'content_source': 'rtb',
+ 'ad_type': 'banner',
+ 'buyer_member_id': 958,
+ 'creative_id': 33989846,
+ 'media_type_id': 1,
+ 'media_subtype_id': 1,
+ 'cpm': 1.99,
+ 'cpm_publisher_currency': 0.500000,
+ 'publisher_currency_code': '$',
+ 'client_initiated_ad_counting': true,
+ 'rtb': {
+ 'banner': {
+ 'width': 300,
+ 'height': 250,
+ 'content': ''
+ },
+ 'trackers': [{
+ 'impression_urls': ['http://lax1-ib.adnxs.com/impression']
+ }]
+ }
+ }]
+ }]
+ };
+ const videoResponse = {
+ 'version': '0.0.1',
+ 'tags': [{
+ 'uuid': '4d0a6829338a07',
+ 'tag_id': 4799418,
+ 'auction_id': '2256922143947979797',
+ 'no_ad_url': 'http://lax1-ib.adnxs.com/no-ad',
+ 'timeout_ms': 2500,
+ 'ads': [{
+ 'content_source': 'rtb',
+ 'ad_type': 'video',
+ 'buyer_member_id': 958,
+ 'creative_id': 33989846,
+ 'media_type_id': 1,
+ 'media_subtype_id': 1,
+ 'cpm': 1.99,
+ 'cpm_publisher_currency': 0.500000,
+ 'publisher_currency_code': '$',
+ 'client_initiated_ad_counting': true,
+ 'rtb': {
+ 'video': {
+ 'width': 300,
+ 'height': 250,
+ 'content': ''
+ },
+ 'trackers': [{
+ 'impression_urls': ['http://lax1-ib.adnxs.com/impression']
+ }]
+ }
+ }]
+ }]
+ };
+
+ const createAdUnit = (code, mediaTypes) => {
+ if (!mediaTypes) {
+ mediaTypes = ['banner'];
+ } else if (typeof mediaTypes === 'string') {
+ mediaTypes = [mediaTypes];
+ }
+
+ const adUnit = {
+ code: code,
+ sizes: [[300, 250], [300, 600]],
+ bids: [{
+ bidder: 'appnexus',
+ params: {
+ placementId: '10433394'
+ }
+ }]
+ };
+
+ let _mediaTypes = {};
+ if (mediaTypes.indexOf('banner') !== -1) {
+ _mediaTypes['banner'] = {
+ 'banner': {}
+ };
+ }
+ if (mediaTypes.indexOf('video') !== -1) {
+ _mediaTypes['video'] = {
+ 'video': {
+ context: 'instream',
+ playerSize: [300, 250]
+ }
+ };
+ }
+ if (mediaTypes.indexOf('native') !== -1) {
+ _mediaTypes['native'] = {
+ 'native': {}
+ };
+ }
+
+ if (Object.keys(_mediaTypes).length > 0) {
+ adUnit['mediaTypes'] = _mediaTypes;
+ // if video type, add video to every bid.param object
+ if (_mediaTypes.video) {
+ adUnit.bids.forEach(bid => {
+ bid.params['video'] = {
+ width: 300,
+ height: 250,
+ vastUrl: '',
+ ttl: 3600
+ };
+ });
+ }
+ }
+ return adUnit;
+ }
+ const initTestConfig = (data) => {
+ $$PREBID_GLOBAL$$.bidderSettings = {};
+
+ ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(function() {
+ return function(url, callback) {
+ const fakeResponse = sinon.stub();
+ fakeResponse.returns('headerContent');
+ callback.success(JSON.stringify(response), { getResponseHeader: fakeResponse });
+ }
+ });
+ auctionManagerInstance = newAuctionManager();
+ targeting = newTargeting(auctionManagerInstance)
+
+ configObj.setConfig({
+ 'priceGranularity': {
+ 'buckets': [
+ { 'precision': 2, 'min': 0, 'max': 5, 'increment': 0.01 },
+ { 'precision': 2, 'min': 5, 'max': 8, 'increment': 0.05 },
+ { 'precision': 2, 'min': 8, 'max': 20, 'increment': 0.5 },
+ { 'precision': 2, 'min': 20, 'max': 25, 'increment': 1 }
+ ]
+ },
+ 'mediaTypePriceGranularity': {
+ 'banner': {
+ 'buckets': [
+ { 'precision': 2, 'min': 0, 'max': 5, 'increment': 0.25 },
+ { 'precision': 2, 'min': 6, 'max': 20, 'increment': 0.5 },
+ { 'precision': 2, 'min': 21, 'max': 100, 'increment': 1 }
+ ]
+ },
+ 'video': 'low',
+ 'native': 'high'
+ }
+ });
+
+ auction = auctionManagerInstance.createAuction({
+ adUnits: data.adUnits,
+ adUnitCodes: data.adUnitCodes
+ });
+ };
+
+ before(() => {
+ currentPriceBucket = configObj.getConfig('priceGranularity');
+ sinon.stub(adaptermanager, 'makeBidRequests').callsFake(() => ([{
+ 'bidderCode': 'appnexus',
+ 'auctionId': '20882439e3238c',
+ 'bidderRequestId': '331f3cf3f1d9c8',
+ 'bids': [
+ {
+ 'bidder': 'appnexus',
+ 'params': {
+ 'placementId': '10433394'
+ },
+ 'adUnitCode': 'div-gpt-ad-1460505748561-0',
+ 'sizes': [
+ [
+ 300,
+ 250
+ ],
+ [
+ 300,
+ 600
+ ]
+ ],
+ 'bidId': '4d0a6829338a07',
+ 'bidderRequestId': '331f3cf3f1d9c8',
+ 'auctionId': '20882439e3238c'
+ }
+ ],
+ 'auctionStart': 1505250713622,
+ 'timeout': 3000
+ }]));
+ });
+
+ after(() => {
+ configObj.setConfig({ priceGranularity: currentPriceBucket });
+ adaptermanager.makeBidRequests.restore();
+ })
+
+ afterEach(() => {
+ ajaxStub.restore();
+ });
+
+ it('should get correct hb_pb with cpm between 0 - 5', () => {
+ initTestConfig({
+ adUnits: [createAdUnit('div-gpt-ad-1460505748561-0')],
+ adUnitCodes: ['div-gpt-ad-1460505748561-0']
+ });
+
+ response = bannerResponse;
+ response.tags[0].ads[0].cpm = 3.4288;
+
+ auction.callBids(cbTimeout);
+ let bidTargeting = targeting.getAllTargeting();
+ expect(bidTargeting['div-gpt-ad-1460505748561-0']['hb_pb']).to.equal('3.25');
+ });
+
+ it('should get correct hb_pb with cpm between 21 - 100', () => {
+ initTestConfig({
+ adUnits: [createAdUnit('div-gpt-ad-1460505748561-0')],
+ adUnitCodes: ['div-gpt-ad-1460505748561-0']
+ });
+
+ response = bannerResponse;
+ response.tags[0].ads[0].cpm = 43.4288;
+
+ auction.callBids(cbTimeout);
+ let bidTargeting = targeting.getAllTargeting();
+ expect(bidTargeting['div-gpt-ad-1460505748561-0']['hb_pb']).to.equal('43.00');
+ });
+
+ it('should only apply price granularity if bid media type matches', () => {
+ initTestConfig({
+ adUnits: [ createAdUnit('div-gpt-ad-1460505748561-0', 'video') ],
+ adUnitCodes: ['div-gpt-ad-1460505748561-0']
+ });
+
+ response = videoResponse;
+ response.tags[0].ads[0].cpm = 3.4288;
+
+ auction.callBids(cbTimeout);
+ let bidTargeting = targeting.getAllTargeting();
+ expect(bidTargeting['div-gpt-ad-1460505748561-0']['hb_pb']).to.equal('3.00');
+ });
+ });
+
describe('getBidResponses', function () {
it('should return expected bid responses when not passed an adunitCode', function () {
var result = $$PREBID_GLOBAL$$.getBidResponses();
From 8314ce218ab2eb60ba98f350596019842d7db14a Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Fri, 18 May 2018 12:01:49 +0200
Subject: [PATCH 27/62] Added click handler for reporting banners click events.
---
modules/rivrAnalyticsAdapter.js | 53 ++++++++++++++++++++++++++-------
1 file changed, 43 insertions(+), 10 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 34eeeed745d..6aa61f296bf 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -2,10 +2,10 @@ import {ajax} from 'src/ajax';
import adapter from 'src/AnalyticsAdapter';
import CONSTANTS from 'src/constants.json';
import adaptermanager from 'src/adaptermanager';
-import { logInfo } from 'src/utils';
+import { logInfo, generateUUID } from 'src/utils';
const analyticsType = 'endpoint';
-const DEFAULT_HOST = 'integrations.rivr.simplaex.net/prebid';
+const DEFAULT_HOST = 'integrations.rivr.simplaex.net';
const DEFAULT_QUEUE_TIMEOUT = 4000;
let rivrAnalytics = Object.assign(adapter({analyticsType}), {
@@ -89,13 +89,13 @@ function trackBidResponse(args) {
function trackBidWon(args) {
let auctionObject = rivrAnalytics.context.auctionObject;
let bidResponse = createBidResponse(args);
- let impression = createImpression(args);
- let imp = createImp(args);
+ let standaloneImpression = createStandaloneImpression(args);
+ let auctionImpression = createAuctionImpression(args);
auctionObject.bidResponses.push(bidResponse);
- auctionObject.imp.push(imp);
+ auctionObject.imp.push(auctionImpression);
- return [impression];
-}
+ return [standaloneImpression];
+};
function trackAuctionEnd(args) {
rivrAnalytics.context.auctionTimeEnd = Date.now();
@@ -136,7 +136,7 @@ function getPlatformType() {
} else {
return 'Desktop';
}
-}
+};
function createBidResponse(bidResponseEvent) {
return {
@@ -167,7 +167,7 @@ function createBidResponse(bidResponseEvent) {
}
};
-function createImpression(bidWonEvent) {
+function createStandaloneImpression(bidWonEvent) {
return {
timestamp: bidWonEvent.responseTimestamp,
requestId: bidWonEvent.auctionId,
@@ -176,7 +176,7 @@ function createImpression(bidWonEvent) {
}
};
-function createImp(bidWonEvent) {
+function createAuctionImpression(bidWonEvent) {
return {
tagid: bidWonEvent.adUnitCode,
displaymanager: null,
@@ -193,6 +193,38 @@ function createImp(bidWonEvent) {
}
};
+function reportClickEvent(event) {
+ let link = event.currentTarget.getElementsByTagName('a')[0];
+ let clickUrl;
+ if (link) {
+ clickUrl = link.getAttribute('href');
+ }
+ let timestamp = new Date().toISOString();
+ let requestId = generateUUID();
+ let req = {
+ timestamp,
+ 'request_id': requestId,
+ 'click_url': clickUrl
+ };
+ logInfo('Sending click events with parameters: ', req);
+ ajax(`http://${rivrAnalytics.context.host}/${window.location.href}/clicks`, () => {
+ }, JSON.stringify(req));
+};
+
+function clickHandler(bannersIds) {
+ setTimeout(function () {
+ bannersIds.forEach(function (bannerId) {
+ var doc = document.getElementById(bannerId);
+ if (doc) {
+ var iframe = doc.getElementsByTagName('iframe')[0];
+ if (iframe) {
+ iframe.contentDocument.addEventListener('click', reportClickEvent);
+ }
+ }
+ });
+ }, 1500);
+};
+
function fulfillAuctionObject() {
return {
id: null,
@@ -310,6 +342,7 @@ rivrAnalytics.enableAnalytics = (config) => {
auctionObject: {},
impressionsQueue: new ExpiringQueue(sendAll, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
+ clickHandler(config.options.bannersIds);
logInfo('Rivr Analytics enabled with config', rivrAnalytics.context);
rivrAnalytics.originEnableAnalytics(config);
};
From cf19b684b57766fb2df96cb6e6e4e38233590924 Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Fri, 18 May 2018 14:06:08 +0200
Subject: [PATCH 28/62] Applied analyzer for reporting displayed impressions.
---
modules/rivrAnalyticsAdapter.js | 78 +++++++++++++++++++--------------
1 file changed, 45 insertions(+), 33 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 6aa61f296bf..574c0077c10 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -17,8 +17,8 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
let handler = null;
switch (eventType) {
case CONSTANTS.EVENTS.AUCTION_INIT:
- if (rivrAnalytics.context.impressionsQueue) {
- rivrAnalytics.context.impressionsQueue.init();
+ if (rivrAnalytics.context.queue) {
+ rivrAnalytics.context.queue.init();
}
if (rivrAnalytics.context.auctionObject) {
rivrAnalytics.context.auctionObject = fulfillAuctionObject();
@@ -43,27 +43,22 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
break;
}
if (handler) {
- if (handler == trackBidWon) {
- let impressions = handler(args);
- if (rivrAnalytics.context.impressionsQueue) {
- rivrAnalytics.context.impressionsQueue.push(impressions);
- }
- } else {
- handler(args)
- }
+ handler(args)
}
}
});
-function sendAll() {
- let impressions = rivrAnalytics.context.impressionsQueue.popAll();
+function sendAuction() {
let auctionObject = rivrAnalytics.context.auctionObject;
let req = Object.assign({}, {Auction: auctionObject});
auctionObject = fulfillAuctionObject();
logInfo('sending request to analytics => ', req);
- ajax(`http://${rivrAnalytics.context.host}/auctions`, () => {
+ ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientURL}/auctions`, () => {
}, JSON.stringify(req));
+};
+function sendImpressions() {
+ let impressions = rivrAnalytics.context.queue.popAll();
if (impressions.length !== 0) {
let impressionsReq = Object.assign({}, {impressions});
logInfo('sending impressions request to analytics => ', impressionsReq);
@@ -89,12 +84,9 @@ function trackBidResponse(args) {
function trackBidWon(args) {
let auctionObject = rivrAnalytics.context.auctionObject;
let bidResponse = createBidResponse(args);
- let standaloneImpression = createStandaloneImpression(args);
let auctionImpression = createAuctionImpression(args);
auctionObject.bidResponses.push(bidResponse);
auctionObject.imp.push(auctionImpression);
-
- return [standaloneImpression];
};
function trackAuctionEnd(args) {
@@ -167,15 +159,6 @@ function createBidResponse(bidResponseEvent) {
}
};
-function createStandaloneImpression(bidWonEvent) {
- return {
- timestamp: bidWonEvent.responseTimestamp,
- requestId: bidWonEvent.auctionId,
- chargePrice: bidWonEvent.adserverTargeting.hb_pb,
- publisherRevenue: bidWonEvent.cpm
- }
-};
-
function createAuctionImpression(bidWonEvent) {
return {
tagid: bidWonEvent.adUnitCode,
@@ -207,16 +190,16 @@ function reportClickEvent(event) {
'click_url': clickUrl
};
logInfo('Sending click events with parameters: ', req);
- ajax(`http://${rivrAnalytics.context.host}/${window.location.href}/clicks`, () => {
+ ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientURL}/clicks`, () => {
}, JSON.stringify(req));
};
function clickHandler(bannersIds) {
setTimeout(function () {
bannersIds.forEach(function (bannerId) {
- var doc = document.getElementById(bannerId);
+ let doc = document.getElementById(bannerId);
if (doc) {
- var iframe = doc.getElementsByTagName('iframe')[0];
+ let iframe = doc.getElementsByTagName('iframe')[0];
if (iframe) {
iframe.contentDocument.addEventListener('click', reportClickEvent);
}
@@ -225,6 +208,32 @@ function clickHandler(bannersIds) {
}, 1500);
};
+function displayedImpressionHandler(bannersIds) {
+ setTimeout(function () {
+ bannersIds.forEach((bannerId) => {
+ let doc = document.getElementById(bannerId);
+ if (doc) {
+ let iframe = doc.getElementsByTagName('iframe')[0];
+ if (iframe) {
+ let displayedImpressionImg = iframe.contentDocument.getElementsByTagName('img').length > 0;
+ if (displayedImpressionImg) {
+ let timestamp = new Date().toISOString();
+ let requestId = generateUUID();
+ let impression = {
+ timestamp,
+ 'request_id': requestId,
+ };
+ if (rivrAnalytics.context.queue) {
+ rivrAnalytics.context.queue.push(impression);
+ }
+ }
+ }
+ }
+ });
+ sendImpressions();
+ }, 3000);
+};
+
function fulfillAuctionObject() {
return {
id: null,
@@ -235,7 +244,7 @@ function fulfillAuctionObject() {
app: {
id: null,
name: null,
- domain: null,
+ domain: rivrAnalytics.context.clientURL,
bundle: null,
cat: [],
publisher: {
@@ -246,7 +255,7 @@ function fulfillAuctionObject() {
site: {
id: null,
name: null,
- domain: window.location.hostname,
+ domain: rivrAnalytics.context.clientURL,
cat: [],
publisher: {
id: null,
@@ -290,7 +299,7 @@ function fulfillAuctionObject() {
* @param ttl
* @constructor
*/
-export function ExpiringQueue(callback, ttl, log) {
+export function ExpiringQueue(sendImpressions, sendAuction, ttl, log) {
let queue = [];
let timeoutId;
@@ -324,8 +333,9 @@ export function ExpiringQueue(callback, ttl, log) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
+ sendAuction();
if (queue.length) {
- callback();
+ sendImpressions();
}
}, ttl);
}
@@ -340,9 +350,11 @@ rivrAnalytics.enableAnalytics = (config) => {
host: config.options.host || DEFAULT_HOST,
pubId: config.options.pubId,
auctionObject: {},
- impressionsQueue: new ExpiringQueue(sendAll, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
+ clientURL: window.location.href,
+ queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
clickHandler(config.options.bannersIds);
+ displayedImpressionHandler(config.options.bannersIds);
logInfo('Rivr Analytics enabled with config', rivrAnalytics.context);
rivrAnalytics.originEnableAnalytics(config);
};
From 3abcf5347b46ac157d3fa9b9f318155a7d8b6b8b Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Tue, 22 May 2018 21:05:28 +0200
Subject: [PATCH 29/62] Applied feedback.
---
modules/rivrAnalyticsAdapter.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 574c0077c10..c1cfec7c1c9 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -194,7 +194,7 @@ function reportClickEvent(event) {
}, JSON.stringify(req));
};
-function clickHandler(bannersIds) {
+function addClickHandlers(bannersIds) {
setTimeout(function () {
bannersIds.forEach(function (bannerId) {
let doc = document.getElementById(bannerId);
@@ -353,7 +353,7 @@ rivrAnalytics.enableAnalytics = (config) => {
clientURL: window.location.href,
queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
- clickHandler(config.options.bannersIds);
+ addClickHandlers(config.options.bannersIds);
displayedImpressionHandler(config.options.bannersIds);
logInfo('Rivr Analytics enabled with config', rivrAnalytics.context);
rivrAnalytics.originEnableAnalytics(config);
From 9d655d2a14631b3e667885bf67d5087f5d4b326f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?=
Date: Thu, 24 May 2018 08:24:30 +0000
Subject: [PATCH 30/62] Merged in RVR-1214-invoke-handlers-on-rendering (pull
request #7)
RVR-1214 Invoke handlers on rendering
* RVR-1214 Invoked handlers right after ad is displayed.
* Applied feedback.
Approved-by: Alessandro Di Giovanni
---
modules/rivrAnalyticsAdapter.js | 93 ++++++++++++++++++++-------------
1 file changed, 56 insertions(+), 37 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index c1cfec7c1c9..04648e3e3cb 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -194,44 +194,64 @@ function reportClickEvent(event) {
}, JSON.stringify(req));
};
-function addClickHandlers(bannersIds) {
- setTimeout(function () {
- bannersIds.forEach(function (bannerId) {
- let doc = document.getElementById(bannerId);
- if (doc) {
- let iframe = doc.getElementsByTagName('iframe')[0];
- if (iframe) {
- iframe.contentDocument.addEventListener('click', reportClickEvent);
- }
- }
- });
- }, 1500);
+function addClickHandler(bannerId) {
+ pinHandlerToHTMLElement(bannerId, dataLoaderForHandler, addClickListener);
};
-function displayedImpressionHandler(bannersIds) {
- setTimeout(function () {
- bannersIds.forEach((bannerId) => {
- let doc = document.getElementById(bannerId);
- if (doc) {
- let iframe = doc.getElementsByTagName('iframe')[0];
- if (iframe) {
- let displayedImpressionImg = iframe.contentDocument.getElementsByTagName('img').length > 0;
- if (displayedImpressionImg) {
- let timestamp = new Date().toISOString();
- let requestId = generateUUID();
- let impression = {
- timestamp,
- 'request_id': requestId,
- };
- if (rivrAnalytics.context.queue) {
- rivrAnalytics.context.queue.push(impression);
- }
- }
- }
+function addDisplayedImpHandler(bannerId) {
+ pinHandlerToHTMLElement(bannerId, dataLoaderForHandler, impHandler);
+};
+
+function pinHandlerToHTMLElement(elementId, dataLoaderForHandler, specializedHandler) {
+ function waitForElement() {
+ let element = document.getElementById(elementId);
+ if (!element) {
+ window.requestAnimationFrame(waitForElement);
+ } else {
+ dataLoaderForHandler(element, specializedHandler);
+ }
+ }
+ waitForElement();
+}
+
+function dataLoaderForHandler(element, specializedHandler) {
+ function waitForElement() {
+ let iframe = element.getElementsByTagName('iframe')[0];
+ if (!iframe) {
+ window.requestAnimationFrame(waitForElement);
+ } else {
+ let displayedImpression = iframe.contentDocument.getElementsByTagName('img').length > 0;
+ if (!displayedImpression) {
+ window.requestAnimationFrame(waitForElement);
+ } else {
+ specializedHandler(iframe);
}
- });
- sendImpressions();
- }, 3000);
+ }
+ }
+ waitForElement();
+};
+
+function addClickListener(iframe) {
+ iframe.contentDocument.addEventListener('click', reportClickEvent);
+}
+
+function impHandler(iframe) {
+ let timestamp = new Date().toISOString();
+ let requestId = generateUUID();
+ let impression = {
+ timestamp,
+ 'request_id': requestId,
+ };
+ if (rivrAnalytics.context.queue) {
+ rivrAnalytics.context.queue.push(impression);
+ }
+}
+
+function addHandlers(bannersIds) {
+ bannersIds.forEach((bannerId) => {
+ addClickHandler(bannerId);
+ addDisplayedImpHandler(bannerId);
+ })
};
function fulfillAuctionObject() {
@@ -353,8 +373,7 @@ rivrAnalytics.enableAnalytics = (config) => {
clientURL: window.location.href,
queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
- addClickHandlers(config.options.bannersIds);
- displayedImpressionHandler(config.options.bannersIds);
+ addHandlers(config.options.bannersIds);
logInfo('Rivr Analytics enabled with config', rivrAnalytics.context);
rivrAnalytics.originEnableAnalytics(config);
};
From 9d2e6c6fcff6a8c2ddea709e29ec89f53dbed8da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?=
Date: Thu, 24 May 2018 09:28:39 +0000
Subject: [PATCH 31/62] Merged in RVR-1192-configuration-global-parameters
(pull request #8)
RVR-1192 Configuration/Global parameters
Approved-by: Alessandro Di Giovanni
---
modules/rivrAnalyticsAdapter.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 04648e3e3cb..35a14c588bc 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -53,7 +53,7 @@ function sendAuction() {
let req = Object.assign({}, {Auction: auctionObject});
auctionObject = fulfillAuctionObject();
logInfo('sending request to analytics => ', req);
- ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientURL}/auctions`, () => {
+ ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`, () => {
}, JSON.stringify(req));
};
@@ -190,7 +190,7 @@ function reportClickEvent(event) {
'click_url': clickUrl
};
logInfo('Sending click events with parameters: ', req);
- ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientURL}/clicks`, () => {
+ ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/clicks`, () => {
}, JSON.stringify(req));
};
@@ -370,7 +370,7 @@ rivrAnalytics.enableAnalytics = (config) => {
host: config.options.host || DEFAULT_HOST,
pubId: config.options.pubId,
auctionObject: {},
- clientURL: window.location.href,
+ clientID: config.options.clientID,
queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
addHandlers(config.options.bannersIds);
From 531fedfe38be02e6ffff298db4c751b964aed5d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?=
Date: Fri, 25 May 2018 09:12:04 +0000
Subject: [PATCH 32/62] Merged in RVR-1181-Prebid-js-unit-tests-setup (pull
request #6)
RVR-1181 Prebid.js Unit tests setup
Approved-by: Alessandro Di Giovanni
---
modules/rivrAnalyticsAdapter.js | 7 +-
.../spec/modules/rivrAnalyticsAdapter_spec.js | 221 ++++++++++++++++++
2 files changed, 224 insertions(+), 4 deletions(-)
create mode 100644 test/spec/modules/rivrAnalyticsAdapter_spec.js
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 35a14c588bc..ea13d233d3e 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -51,7 +51,7 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
function sendAuction() {
let auctionObject = rivrAnalytics.context.auctionObject;
let req = Object.assign({}, {Auction: auctionObject});
- auctionObject = fulfillAuctionObject();
+ rivrAnalytics.context.auctionObject = fulfillAuctionObject();
logInfo('sending request to analytics => ', req);
ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`, () => {
}, JSON.stringify(req));
@@ -83,9 +83,7 @@ function trackBidResponse(args) {
function trackBidWon(args) {
let auctionObject = rivrAnalytics.context.auctionObject;
- let bidResponse = createBidResponse(args);
let auctionImpression = createAuctionImpression(args);
- auctionObject.bidResponses.push(bidResponse);
auctionObject.imp.push(auctionImpression);
};
@@ -255,7 +253,7 @@ function addHandlers(bannersIds) {
};
function fulfillAuctionObject() {
- return {
+ let newAuction = {
id: null,
timestamp: null,
at: null,
@@ -312,6 +310,7 @@ function fulfillAuctionObject() {
},
bidResponses: []
}
+ return newAuction;
};
/**
* Expiring queue implementation. Fires callback on elapsed timeout since last last update or creation.
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
new file mode 100644
index 00000000000..b0d3b2fd72f
--- /dev/null
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -0,0 +1,221 @@
+import analyticsAdapter, {ExpiringQueue} from 'modules/rivrAnalyticsAdapter';
+import {expect} from 'chai';
+import adaptermanager from 'src/adaptermanager';
+import * as ajax from 'src/ajax';
+import CONSTANTS from 'src/constants.json';
+
+const events = require('../../../src/events');
+
+describe('', () => {
+ let sandbox;
+
+ before(() => {
+ sandbox = sinon.sandbox.create();
+ });
+
+ after(() => {
+ sandbox.restore();
+ analyticsAdapter.disableAnalytics();
+ });
+
+ describe('ExpiringQueue', () => {
+ let timer;
+ before(() => {
+ timer = sandbox.useFakeTimers(0);
+ });
+ after(() => {
+ timer.restore();
+ });
+
+ it('should notify after timeout period', (done) => {
+ let queue = new ExpiringQueue(() => {
+ let elements = queue.popAll();
+ expect(elements).to.be.eql([1, 2, 3, 4]);
+ elements = queue.popAll();
+ expect(elements).to.have.lengthOf(0);
+ expect(Date.now()).to.be.equal(200);
+ done();
+ }, () => {}, 100);
+
+ queue.push(1);
+ setTimeout(() => {
+ queue.push([2, 3]);
+ timer.tick(50);
+ }, 50);
+ setTimeout(() => {
+ queue.push([4]);
+ timer.tick(100);
+ }, 100);
+ timer.tick(50);
+ });
+ });
+
+ const REQUEST = {
+ bidderCode: 'adapter',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
+ bidderRequestId: '1a6fc81528d0f6',
+ bids: [{
+ bidder: 'adapter',
+ params: {},
+ adUnitCode: 'container-1',
+ transactionId: 'de90df62-7fd0-4fbc-8787-92d133a7dc06',
+ sizes: [[300, 250]],
+ bidId: '208750227436c1',
+ bidderRequestId: '1a6fc81528d0f6',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f'
+ }],
+ auctionStart: 1509369418387,
+ timeout: 3000,
+ start: 1509369418389
+ };
+
+ const RESPONSE = {
+ bidderCode: 'adapter',
+ width: 300,
+ height: 250,
+ statusMessage: 'Bid available',
+ getStatusCode: () => 1,
+ adId: '208750227436c1',
+ mediaType: 'banner',
+ cpm: 0.015,
+ creativeId: 999,
+ ad: '',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
+ responseTimestamp: 1509369418832,
+ requestTimestamp: 1509369418389,
+ bidder: 'adapter',
+ adUnitCode: 'container-1',
+ timeToRespond: 443,
+ currency: 'EU',
+ size: '300x250'
+ };
+
+ describe('Analytics adapter', () => {
+ let ajaxStub;
+ let timer;
+
+ before(() => {
+ ajaxStub = sandbox.stub(ajax, 'ajax');
+ timer = sandbox.useFakeTimers(0);
+ });
+
+ beforeEach(() => {
+ sandbox.stub(events, 'getEvents').callsFake(() => {
+ return []
+ });
+ });
+
+ afterEach(() => {
+ events.getEvents.restore();
+ });
+
+ it('should be configurable', () => {
+ adaptermanager.registerAnalyticsAdapter({
+ code: 'rivr',
+ adapter: analyticsAdapter
+ });
+
+ adaptermanager.enableAnalytics({
+ provider: 'rivr',
+ options: {
+ pubId: 777,
+ }
+ });
+
+ expect(analyticsAdapter.context).to.have.property('host', 'integrations.rivr.simplaex.net');
+ expect(analyticsAdapter.context).to.have.property('pubId', 777);
+ });
+
+ it('should handle auction init event', () => {
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 1, config: {}, timeout: 3000});
+ const auctionId = analyticsAdapter.context.auctionObject.id;
+ const auctionStart = analyticsAdapter.context.auctionTimeStart;
+ expect(auctionId).to.be.eql(1);
+ });
+
+ it('should handle bid request event', () => {
+ events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
+ const sitePubcid = analyticsAdapter.context.auctionObject.site.publisher.id;
+ const appPubcid = analyticsAdapter.context.auctionObject.app.publisher.id;
+ expect(sitePubcid).to.be.eql(777);
+ expect(sitePubcid).to.be.eql(appPubcid);
+ });
+
+ it('should handle bid response event', () => {
+ events.emit(CONSTANTS.EVENTS.BID_RESPONSE, RESPONSE);
+ const ev = analyticsAdapter.context.auctionObject.bidResponses;
+ expect(ev).to.have.length(1);
+ expect(ev[0]).to.be.eql({
+ timestamp: 1509369418832,
+ status: 1,
+ 'total_duration': 443,
+ bidderId: null,
+ 'bidder_name': 'adapter',
+ cur: 'EU',
+ seatid: [
+ {
+ seat: null,
+ bid: [
+ {
+ status: 1,
+ 'clear_price': 0.015,
+ attr: [],
+ crid: 999,
+ cid: null,
+ id: null,
+ adid: '208750227436c1',
+ adomain: [],
+ iurl: null
+ }
+ ]
+ }
+ ]
+ });
+ });
+
+ it('should handle auction end event', () => {
+ timer.tick(447);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, RESPONSE);
+ const endTime = analyticsAdapter.context.auctionTimeEnd;
+ expect(endTime).to.be.eql(447);
+ });
+
+ it('should handle winning bid', () => {
+ events.emit(CONSTANTS.EVENTS.BID_WON, RESPONSE);
+ const ev = analyticsAdapter.context.auctionObject.imp;
+ expect(ev.length).to.be.eql(1);
+ expect(ev[0]).to.be.eql({
+ tagid: 'container-1',
+ displaymanager: null,
+ displaymanagerver: null,
+ secure: null,
+ bidfloor: null,
+ banner: {
+ w: 300,
+ h: 250,
+ pos: null,
+ expandable: [],
+ api: []
+ }
+ });
+ });
+
+ it('sends request after timeout', () => {
+ let impressions = analyticsAdapter.context.auctionObject.imp;
+ let responses = analyticsAdapter.context.auctionObject.bidResponses;
+
+ expect(impressions.length).to.be.eql(1);
+ expect(responses.length).to.be.eql(1);
+ expect(ajaxStub.calledOnce).to.be.equal(false);
+
+ timer.tick(4500);
+
+ let impressionss = analyticsAdapter.context.auctionObject.imp;
+ let responsess = analyticsAdapter.context.auctionObject.bidResponses;
+
+ expect(ajaxStub.calledOnce).to.be.equal(true);
+ expect(impressionss.length).to.be.eql(0);
+ expect(responsess.length).to.be.eql(0);
+ });
+ });
+});
From f70992fb0971a517938aada4371ea22717c3f887 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?=
Date: Fri, 25 May 2018 09:12:42 +0000
Subject: [PATCH 33/62] Merged in
RVR-1247-additional-data-to-impression-records (pull request #9)
RVR-1247 Additional data to impression records
Approved-by: Alessandro Di Giovanni
---
modules/rivrAnalyticsAdapter.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index ea13d233d3e..3ef6d325ad3 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -236,9 +236,11 @@ function addClickListener(iframe) {
function impHandler(iframe) {
let timestamp = new Date().toISOString();
let requestId = generateUUID();
+ let adContainerId = iframe.parentElement.parentElement.id;
let impression = {
timestamp,
'request_id': requestId,
+ 'tag_id': adContainerId
};
if (rivrAnalytics.context.queue) {
rivrAnalytics.context.queue.push(impression);
From ddbd01803a08b0273582e4ff93fdea035c31efc7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?=
Date: Fri, 25 May 2018 09:13:27 +0000
Subject: [PATCH 34/62] Merged in RVR-1249-add-requestedbids-to-auction (pull
request #10)
RVR-1249 Add requested bids to auction object request.
Approved-by: Alessandro Di Giovanni
---
modules/rivrAnalyticsAdapter.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 3ef6d325ad3..b9222bdc0f1 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -74,6 +74,8 @@ function trackAuctionInit(args) {
function trackBidRequest(args) {
setCurrentPublisherId(args);
+ let bidRequest = args;
+ rivrAnalytics.context.auctionObject.bidRequests.push(bidRequest);
};
function trackBidResponse(args) {
@@ -310,7 +312,8 @@ function fulfillAuctionObject() {
yob: null,
gender: null,
},
- bidResponses: []
+ bidResponses: [],
+ bidRequests: []
}
return newAuction;
};
From e7e28acfa3b89a300258c89ed47440ed7a97dce2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?=
Date: Wed, 30 May 2018 09:42:04 +0000
Subject: [PATCH 35/62] Merged in RVR-1261-fix-tests (pull request #11)
RVR-1261 fix tests
* RVR-1261 Secured adapter from no containers configuration. And changed fetching URL.
* RVR-1261 Added event check for request and changed some names.
* Applied feedback.
Approved-by: Alessandro Di Giovanni
---
modules/rivrAnalyticsAdapter.js | 12 +++--
.../spec/modules/rivrAnalyticsAdapter_spec.js | 44 ++++++++++++++-----
2 files changed, 42 insertions(+), 14 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index b9222bdc0f1..575bf996bd3 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -266,7 +266,7 @@ function fulfillAuctionObject() {
app: {
id: null,
name: null,
- domain: rivrAnalytics.context.clientURL,
+ domain: window.location.href,
bundle: null,
cat: [],
publisher: {
@@ -277,7 +277,7 @@ function fulfillAuctionObject() {
site: {
id: null,
name: null,
- domain: rivrAnalytics.context.clientURL,
+ domain: window.location.href,
cat: [],
publisher: {
id: null,
@@ -293,7 +293,6 @@ function fulfillAuctionObject() {
type: null,
metro: null
},
- connectiontype: navigator.connection.effectiveType,
devicetype: getPlatformType(),
osv: null,
os: null,
@@ -377,7 +376,12 @@ rivrAnalytics.enableAnalytics = (config) => {
clientID: config.options.clientID,
queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
- addHandlers(config.options.bannersIds);
+ let bannersIds = config.options.bannersIds
+ if (bannersIds) {
+ if (bannersIds.length > 0) {
+ addHandlers(config.options.bannersIds);
+ }
+ }
logInfo('Rivr Analytics enabled with config', rivrAnalytics.context);
rivrAnalytics.originEnableAnalytics(config);
};
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index b0d3b2fd72f..7c2bb55e155 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -137,15 +137,35 @@ describe('', () => {
events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
const sitePubcid = analyticsAdapter.context.auctionObject.site.publisher.id;
const appPubcid = analyticsAdapter.context.auctionObject.app.publisher.id;
+ const requestEvent = analyticsAdapter.context.auctionObject.bidRequests;
expect(sitePubcid).to.be.eql(777);
expect(sitePubcid).to.be.eql(appPubcid);
+ expect(requestEvent).to.have.length(1);
+ expect(requestEvent[0]).to.be.eql({
+ bidderCode: 'adapter',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
+ bidderRequestId: '1a6fc81528d0f6',
+ bids: [{
+ bidder: 'adapter',
+ params: {},
+ adUnitCode: 'container-1',
+ transactionId: 'de90df62-7fd0-4fbc-8787-92d133a7dc06',
+ sizes: [[300, 250]],
+ bidId: '208750227436c1',
+ bidderRequestId: '1a6fc81528d0f6',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f'
+ }],
+ auctionStart: 1509369418387,
+ timeout: 3000,
+ start: 1509369418389
+ });
});
it('should handle bid response event', () => {
events.emit(CONSTANTS.EVENTS.BID_RESPONSE, RESPONSE);
- const ev = analyticsAdapter.context.auctionObject.bidResponses;
- expect(ev).to.have.length(1);
- expect(ev[0]).to.be.eql({
+ const responseEvent = analyticsAdapter.context.auctionObject.bidResponses;
+ expect(responseEvent).to.have.length(1);
+ expect(responseEvent[0]).to.be.eql({
timestamp: 1509369418832,
status: 1,
'total_duration': 443,
@@ -182,9 +202,9 @@ describe('', () => {
it('should handle winning bid', () => {
events.emit(CONSTANTS.EVENTS.BID_WON, RESPONSE);
- const ev = analyticsAdapter.context.auctionObject.imp;
- expect(ev.length).to.be.eql(1);
- expect(ev[0]).to.be.eql({
+ const wonEvent = analyticsAdapter.context.auctionObject.imp;
+ expect(wonEvent.length).to.be.eql(1);
+ expect(wonEvent[0]).to.be.eql({
tagid: 'container-1',
displaymanager: null,
displaymanagerver: null,
@@ -203,19 +223,23 @@ describe('', () => {
it('sends request after timeout', () => {
let impressions = analyticsAdapter.context.auctionObject.imp;
let responses = analyticsAdapter.context.auctionObject.bidResponses;
+ let requests = analyticsAdapter.context.auctionObject.bidRequests;
expect(impressions.length).to.be.eql(1);
expect(responses.length).to.be.eql(1);
+ expect(requests.length).to.be.eql(1);
expect(ajaxStub.calledOnce).to.be.equal(false);
timer.tick(4500);
- let impressionss = analyticsAdapter.context.auctionObject.imp;
- let responsess = analyticsAdapter.context.auctionObject.bidResponses;
+ let impressionsAfterSend = analyticsAdapter.context.auctionObject.imp;
+ let responsesAfterSend = analyticsAdapter.context.auctionObject.bidResponses;
+ let requestsAfterSend = analyticsAdapter.context.auctionObject.bidRequests;
expect(ajaxStub.calledOnce).to.be.equal(true);
- expect(impressionss.length).to.be.eql(0);
- expect(responsess.length).to.be.eql(0);
+ expect(impressionsAfterSend.length).to.be.eql(0);
+ expect(responsesAfterSend.length).to.be.eql(0);
+ expect(requestsAfterSend.length).to.be.eql(0);
});
});
});
From 3b2d283436c75e77cab801a45556456f2adb10db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?=
Date: Wed, 13 Jun 2018 08:55:11 +0000
Subject: [PATCH 36/62] RVR-1352 analytics adapter bugs
Approved-by: Alessandro Di Giovanni
---
modules/rivrAnalyticsAdapter.js | 53 +++++++++++-
.../spec/modules/rivrAnalyticsAdapter_spec.js | 82 ++++++++++++++++++-
2 files changed, 129 insertions(+), 6 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 575bf996bd3..854ee311aab 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -87,10 +87,12 @@ function trackBidWon(args) {
let auctionObject = rivrAnalytics.context.auctionObject;
let auctionImpression = createAuctionImpression(args);
auctionObject.imp.push(auctionImpression);
+ assignBidWonStatusToResponse(args);
};
function trackAuctionEnd(args) {
rivrAnalytics.context.auctionTimeEnd = Date.now();
+ createEmptyBidResponses();
};
function trackBidTimeout(args) {
@@ -138,12 +140,12 @@ function createBidResponse(bidResponseEvent) {
bidderId: null,
bidder_name: bidResponseEvent.bidder,
cur: bidResponseEvent.currency,
- seatid: [
+ seatbid: [
{
seat: null,
bid: [
{
- status: bidResponseEvent.getStatusCode(),
+ status: 2,
clear_price: bidResponseEvent.cpm,
attr: [],
crid: bidResponseEvent.creativeId,
@@ -159,6 +161,18 @@ function createBidResponse(bidResponseEvent) {
}
};
+function createSingleEmptyBidResponse(bidResponse) {
+ return {
+ timestamp: bidResponse.start,
+ total_duration: 'noResponseDuration',
+ bidderId: null,
+ bidder_name: bidResponse.bidder,
+ cur: null,
+ response: 'noBid',
+ seatbid: []
+ }
+};
+
function createAuctionImpression(bidWonEvent) {
return {
tagid: bidWonEvent.adUnitCode,
@@ -364,6 +378,41 @@ export function ExpiringQueue(sendImpressions, sendAuction, ttl, log) {
}
};
+function assignBidWonStatusToResponse(wonBid) {
+ let wonBidId = wonBid.adId;
+ rivrAnalytics.context.auctionObject.bidResponses.forEach((response) => {
+ if (response.seatbid.length > 0) {
+ let bidObjectResponse = response.seatbid[0].bid[0];
+ if (wonBidId === bidObjectResponse.adid) {
+ bidObjectResponse.status = 1
+ }
+ }
+ });
+};
+
+function createEmptyBidResponses() {
+ let unRespondedBidRequests = findAllUnrespondedBidRequests();
+ unRespondedBidRequests.forEach((bid) => {
+ let emptyBidResponse = createSingleEmptyBidResponse(bid);
+ rivrAnalytics.context.auctionObject.bidResponses.push(emptyBidResponse);
+ });
+};
+
+function findAllUnrespondedBidRequests() {
+ let respondedBidIds = getAllRespondedBidIds();
+ let bidRequests = rivrAnalytics.context.auctionObject.bidRequests;
+ let allNotRespondedBidRequests = bidRequests.reduce((cache, requestBidder) => {
+ let notRespondedBids = requestBidder.bids.filter((bid) => !respondedBidIds.includes(bid.bidId));
+ notRespondedBids.forEach((bid) => bid.start = requestBidder.start);
+ return cache.concat(notRespondedBids);
+ }, []);
+ return allNotRespondedBidRequests;
+};
+
+function getAllRespondedBidIds() {
+ return rivrAnalytics.context.auctionObject.bidResponses.map((response) => response.seatbid[0].bid[0].adid);
+};
+
// save the base class function
rivrAnalytics.originEnableAnalytics = rivrAnalytics.enableAnalytics;
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 7c2bb55e155..d4bf1c344e8 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -69,6 +69,44 @@ describe('', () => {
start: 1509369418389
};
+ const REQUEST2 = {
+ bidderCode: 'adapter',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
+ bidderRequestId: '1a6fc81528d0f6',
+ bids: [{
+ bidder: 'adapter',
+ params: {},
+ adUnitCode: 'container-1',
+ transactionId: 'de90df62-7fd0-4fbc-8787-92d133a7dc06',
+ sizes: [[300, 250]],
+ bidId: 'request2id',
+ bidderRequestId: '1a6fc81528d0f6',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f'
+ }],
+ auctionStart: 1509369418387,
+ timeout: 3000,
+ start: 1509369418389
+ };
+
+ const REQUEST3 = {
+ bidderCode: 'adapter',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
+ bidderRequestId: '1a6fc81528d0f6',
+ bids: [{
+ bidder: 'adapter',
+ params: {},
+ adUnitCode: 'container-1',
+ transactionId: 'de90df62-7fd0-4fbc-8787-92d133a7dc06',
+ sizes: [[300, 250]],
+ bidId: 'request3id',
+ bidderRequestId: '1a6fc81528d0f6',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f'
+ }],
+ auctionStart: 1509369418387,
+ timeout: 3000,
+ start: 1509369418389
+ };
+
const RESPONSE = {
bidderCode: 'adapter',
width: 300,
@@ -172,12 +210,12 @@ describe('', () => {
bidderId: null,
'bidder_name': 'adapter',
cur: 'EU',
- seatid: [
+ seatbid: [
{
seat: null,
bid: [
{
- status: 1,
+ status: 2,
'clear_price': 0.015,
attr: [],
crid: 999,
@@ -200,8 +238,17 @@ describe('', () => {
expect(endTime).to.be.eql(447);
});
+ it('should map unresponded requests to empty responded on auction end', () => {
+ events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST2);
+ events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST3);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, RESPONSE);
+ const responses = analyticsAdapter.context.auctionObject.bidResponses;
+ expect(responses.length).to.be.eql(3);
+ })
+
it('should handle winning bid', () => {
events.emit(CONSTANTS.EVENTS.BID_WON, RESPONSE);
+ const responseWhichIsWonAlso = analyticsAdapter.context.auctionObject.bidResponses[0];
const wonEvent = analyticsAdapter.context.auctionObject.imp;
expect(wonEvent.length).to.be.eql(1);
expect(wonEvent[0]).to.be.eql({
@@ -218,6 +265,33 @@ describe('', () => {
api: []
}
});
+
+ expect(responseWhichIsWonAlso).to.be.eql({
+ timestamp: 1509369418832,
+ status: 1,
+ 'total_duration': 443,
+ bidderId: null,
+ 'bidder_name': 'adapter',
+ cur: 'EU',
+ seatbid: [
+ {
+ seat: null,
+ bid: [
+ {
+ status: 1,
+ 'clear_price': 0.015,
+ attr: [],
+ crid: 999,
+ cid: null,
+ id: null,
+ adid: '208750227436c1',
+ adomain: [],
+ iurl: null
+ }
+ ]
+ }
+ ]
+ });
});
it('sends request after timeout', () => {
@@ -226,8 +300,8 @@ describe('', () => {
let requests = analyticsAdapter.context.auctionObject.bidRequests;
expect(impressions.length).to.be.eql(1);
- expect(responses.length).to.be.eql(1);
- expect(requests.length).to.be.eql(1);
+ expect(responses.length).to.be.eql(3);
+ expect(requests.length).to.be.eql(3);
expect(ajaxStub.calledOnce).to.be.equal(false);
timer.tick(4500);
From 5f692b21dbaf36a9f29fc13b070efd60b28b0443 Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Wed, 13 Jun 2018 14:27:17 +0200
Subject: [PATCH 37/62] Fixed bug with geolocation notification.
---
modules/rivrAnalyticsAdapter.js | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 854ee311aab..55552420278 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -115,12 +115,15 @@ function setCurrentPublisherId(bidRequested) {
};
function fetchLocalization() {
- navigator.geolocation.getCurrentPosition((position) => {
- let deviceLocation = rivrAnalytics.context.auctionObject.device.geo;
- deviceLocation.lat = position.coords.latitude;
- deviceLocation.long = position.coords.longitude;
+ navigator.permissions.query({ name: 'geolocation' }).then(function (permission) {
+ if (permission.status === 'granted') {
+ navigator.geolocation.getCurrentPosition((position) => {
+ let deviceLocation = rivrAnalytics.context.auctionObject.device.geo;
+ deviceLocation.lat = position.coords.latitude;
+ deviceLocation.long = position.coords.longitude;
+ });
+ }
});
-};
function getPlatformType() {
if (navigator.userAgent.match(/mobile/i)) {
From 9c98d85618a960da8f00d98a29283b919e9d4bae Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Wed, 13 Jun 2018 14:35:46 +0200
Subject: [PATCH 38/62] fixed missing bracket.
---
modules/rivrAnalyticsAdapter.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 55552420278..005e4c25a77 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -115,7 +115,7 @@ function setCurrentPublisherId(bidRequested) {
};
function fetchLocalization() {
- navigator.permissions.query({ name: 'geolocation' }).then(function (permission) {
+ navigator.permissions.query({ name: 'geolocation' }).then((permission) => {
if (permission.status === 'granted') {
navigator.geolocation.getCurrentPosition((position) => {
let deviceLocation = rivrAnalytics.context.auctionObject.device.geo;
@@ -124,6 +124,7 @@ function fetchLocalization() {
});
}
});
+}
function getPlatformType() {
if (navigator.userAgent.match(/mobile/i)) {
From eb6bba3f495d8749aaf4f9040c01981397061fda Mon Sep 17 00:00:00 2001
From: Wozniaxos
Date: Wed, 13 Jun 2018 14:46:43 +0200
Subject: [PATCH 39/62] one more fix.
---
modules/rivrAnalyticsAdapter.js | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 005e4c25a77..b3a4c0f66ca 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -115,15 +115,17 @@ function setCurrentPublisherId(bidRequested) {
};
function fetchLocalization() {
- navigator.permissions.query({ name: 'geolocation' }).then((permission) => {
- if (permission.status === 'granted') {
- navigator.geolocation.getCurrentPosition((position) => {
- let deviceLocation = rivrAnalytics.context.auctionObject.device.geo;
- deviceLocation.lat = position.coords.latitude;
- deviceLocation.long = position.coords.longitude;
- });
- }
- });
+ if (navigator.permissions) {
+ navigator.permissions.query({ name: 'geolocation' }).then((permission) => {
+ if (permission.status === 'granted') {
+ navigator.geolocation.getCurrentPosition((position) => {
+ let deviceLocation = rivrAnalytics.context.auctionObject.device.geo;
+ deviceLocation.lat = position.coords.latitude;
+ deviceLocation.long = position.coords.longitude;
+ });
+ }
+ });
+ }
}
function getPlatformType() {
From f654565a7b0fe9a4d1026aab0128f50d78336307 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?=
Date: Tue, 26 Jun 2018 11:58:38 +0000
Subject: [PATCH 40/62] RVR-1357 Different optimisation responses & tracking
into auction event
---
modules/rivrAnalyticsAdapter.js | 61 ++++++++++++++++++-
.../spec/modules/rivrAnalyticsAdapter_spec.js | 20 ++++++
2 files changed, 80 insertions(+), 1 deletion(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index b3a4c0f66ca..708bc957a9c 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -22,6 +22,7 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
}
if (rivrAnalytics.context.auctionObject) {
rivrAnalytics.context.auctionObject = fulfillAuctionObject();
+ saveUnoptimisedParams();
fetchLocalization();
}
handler = trackAuctionInit;
@@ -332,10 +333,62 @@ function fulfillAuctionObject() {
gender: null,
},
bidResponses: [],
- bidRequests: []
+ bidRequests: [],
+ 'ext.rivr.optimiser': localStorage.getItem('rivr_should_optimise') || 'unoptimised',
+ modelVersion: localStorage.getItem('rivr_model_version') || null,
+ 'ext.rivr.originalvalues': []
}
return newAuction;
};
+
+function saveUnoptimisedParams() {
+ let units = rivrAnalytics.context.adUnits;
+ if (units) {
+ if (units.length > 0) {
+ let allUnits = connectAllUnits(units);
+ allUnits.forEach((adUnit) => {
+ adUnit.bids.forEach((bid) => {
+ let configForAd = fetchConfigForBidder(bid.bidder);
+ if (configForAd) {
+ let unOptimisedParamsField = createUnOptimisedParamsField(bid, configForAd)
+ rivrAnalytics.context.auctionObject['ext.rivr.originalvalues'].push(unOptimisedParamsField);
+ }
+ })
+ });
+ }
+ }
+};
+
+function connectAllUnits(units) {
+ return units.reduce((acc, units) => {
+ units.forEach((unit) => acc.push(unit))
+ return acc
+ }, []);
+}
+
+function createUnOptimisedParamsField(unit, config) {
+ let floorPriceLabel = config['floorPriceLabel'];
+ let currencyLabel = config['currencyLabel'];
+ let pmpLabel = config['pmpLabel'];
+ return {
+ 'ext.rivr.demand_source_original': unit.bidder,
+ 'ext.rivr.bidfloor_original': unit.params[floorPriceLabel],
+ 'ext.rivr.currency_original': unit.params[currencyLabel],
+ 'ext.rivr.pmp_original': unit.params[pmpLabel],
+ }
+}
+
+function fetchConfigForBidder(bidderName) {
+ let config = localStorage.getItem('rivr_config_string');
+ if (config) {
+ let parsed = JSON.parse(config);
+ return parsed.demand.map((bidderConfig) => {
+ if (bidderName === bidderConfig.partner) {
+ return bidderConfig
+ };
+ })[0];
+ }
+}
/**
* Expiring queue implementation. Fires callback on elapsed timeout since last last update or creation.
* @param callback
@@ -424,10 +477,16 @@ rivrAnalytics.originEnableAnalytics = rivrAnalytics.enableAnalytics;
// override enableAnalytics so we can get access to the config passed in from the page
rivrAnalytics.enableAnalytics = (config) => {
+ let copiedUnits;
+ if (config.options.adUnits) {
+ let stringifiedAdUnits = JSON.stringify(config.options.adUnits);
+ copiedUnits = JSON.parse(stringifiedAdUnits);
+ }
rivrAnalytics.context = {
host: config.options.host || DEFAULT_HOST,
pubId: config.options.pubId,
auctionObject: {},
+ adUnits: copiedUnits,
clientID: config.options.clientID,
queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index d4bf1c344e8..00bcfbc5357 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -171,6 +171,26 @@ describe('', () => {
expect(auctionId).to.be.eql(1);
});
+ it('should map proper response params on auction init', () => {
+ localStorage.setItem('rivr_should_optimise', 'optimise')
+ localStorage.setItem('rivr_model_version', 'some model version');
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 2, config: {}, timeout: 3000});
+ let auctionObject2 = analyticsAdapter.context.auctionObject;
+
+ expect(auctionObject2['ext.rivr.optimiser']).to.be.eql('optimise');
+ expect(auctionObject2['modelVersion']).to.be.eql('some model version');
+
+ localStorage.removeItem('rivr_should_optimise');
+ localStorage.removeItem('rivr_model_version');
+
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 3, config: {}, timeout: 3000});
+
+ let auctionObject3 = analyticsAdapter.context.auctionObject;
+
+ expect(auctionObject3['ext.rivr.optimiser']).to.be.eql('unoptimised');
+ expect(auctionObject3['modelVersion']).to.be.eql(null);
+ })
+
it('should handle bid request event', () => {
events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
const sitePubcid = analyticsAdapter.context.auctionObject.site.publisher.id;
From 2a3923a2bd79fb2633a5d90dbf383c28afdac93e Mon Sep 17 00:00:00 2001
From: adg
Date: Thu, 30 Aug 2018 17:50:34 +0200
Subject: [PATCH 41/62] RVR-1852 - Add content type and hardcoded auth headers
(cherry picked from commit 4def881)
---
modules/rivrAnalyticsAdapter.js | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 708bc957a9c..91b01d2362f 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -54,8 +54,17 @@ function sendAuction() {
let req = Object.assign({}, {Auction: auctionObject});
rivrAnalytics.context.auctionObject = fulfillAuctionObject();
logInfo('sending request to analytics => ', req);
- ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`, () => {
- }, JSON.stringify(req));
+ ajax(
+ `http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`,
+ () => {},
+ JSON.stringify(req),
+ {
+ customHeaders: {
+ 'Authorization': 'Basic b3V0ZXJwYXNzaXZlOkQ3OVZ5YXI1eVZXUEVBaHI=',
+ 'Content-type': 'application/json'
+ }
+ }
+ );
};
function sendImpressions() {
@@ -63,8 +72,17 @@ function sendImpressions() {
if (impressions.length !== 0) {
let impressionsReq = Object.assign({}, {impressions});
logInfo('sending impressions request to analytics => ', impressionsReq);
- ajax(`http://${rivrAnalytics.context.host}/impressions`, () => {
- }, JSON.stringify(impressionsReq));
+ ajax(
+ `http://${rivrAnalytics.context.host}/impressions`,
+ () => {},
+ JSON.stringify(impressionsReq),
+ {
+ customHeaders: {
+ 'Authorization': 'Basic b3V0ZXJwYXNzaXZlOkQ3OVZ5YXI1eVZXUEVBaHI=',
+ 'Content-type': 'application/json'
+ }
+ }
+ );
}
};
From ebf8f54cdb2ae137f23232f644f238327618b908 Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 31 Aug 2018 14:09:20 +0200
Subject: [PATCH 42/62] RVR-1852 - Change tracker host
---
modules/rivrAnalyticsAdapter.js | 2 +-
test/spec/modules/rivrAnalyticsAdapter_spec.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 91b01d2362f..1d13ffe944d 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -5,7 +5,7 @@ import adaptermanager from 'src/adaptermanager';
import { logInfo, generateUUID } from 'src/utils';
const analyticsType = 'endpoint';
-const DEFAULT_HOST = 'integrations.rivr.simplaex.net';
+const DEFAULT_HOST = 'tracker.rivr.simplaex.com';
const DEFAULT_QUEUE_TIMEOUT = 4000;
let rivrAnalytics = Object.assign(adapter({analyticsType}), {
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 00bcfbc5357..c52711f6ee9 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -160,7 +160,7 @@ describe('', () => {
}
});
- expect(analyticsAdapter.context).to.have.property('host', 'integrations.rivr.simplaex.net');
+ expect(analyticsAdapter.context).to.have.property('host', 'tracker.rivr.simplaex.com');
expect(analyticsAdapter.context).to.have.property('pubId', 777);
});
From 07bc09f25f07173865e3b11b4dc8af8db89bde63 Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 31 Aug 2018 14:25:06 +0200
Subject: [PATCH 43/62] RVR-1852 - Override content type instead of adding
header
---
modules/rivrAnalyticsAdapter.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 1d13ffe944d..f3afde6ba95 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -59,9 +59,9 @@ function sendAuction() {
() => {},
JSON.stringify(req),
{
+ contentType: 'application/json',
customHeaders: {
- 'Authorization': 'Basic b3V0ZXJwYXNzaXZlOkQ3OVZ5YXI1eVZXUEVBaHI=',
- 'Content-type': 'application/json'
+ 'Authorization': 'Basic b3V0ZXJwYXNzaXZlOkQ3OVZ5YXI1eVZXUEVBaHI='
}
}
);
@@ -77,9 +77,9 @@ function sendImpressions() {
() => {},
JSON.stringify(impressionsReq),
{
+ contentType: 'application/json',
customHeaders: {
- 'Authorization': 'Basic b3V0ZXJwYXNzaXZlOkQ3OVZ5YXI1eVZXUEVBaHI=',
- 'Content-type': 'application/json'
+ 'Authorization': 'Basic b3V0ZXJwYXNzaXZlOkQ3OVZ5YXI1eVZXUEVBaHI='
}
}
);
From 53d2493f51d280c3deb712f830a4311727fc7b4f Mon Sep 17 00:00:00 2001
From: Alessandro Di Giovanni
Date: Thu, 13 Sep 2018 15:14:40 +0000
Subject: [PATCH 44/62] RVR-1914 Consistent data types in events
Also removes undefined and null properties in audience events
---
modules/rivrAnalyticsAdapter.js | 24 ++++++++++++++-----
.../spec/modules/rivrAnalyticsAdapter_spec.js | 21 +++++++++++++++-
2 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index f3afde6ba95..ca64d4710bf 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -49,7 +49,9 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
}
});
-function sendAuction() {
+export function sendAuction() {
+ console.log('Function called: ============= sendAuction');
+ removeEmptyProperties(rivrAnalytics.context.auctionObject)
let auctionObject = rivrAnalytics.context.auctionObject;
let req = Object.assign({}, {Auction: auctionObject});
rivrAnalytics.context.auctionObject = fulfillAuctionObject();
@@ -68,6 +70,7 @@ function sendAuction() {
};
function sendImpressions() {
+ console.log('Function called: ============= sendImpressions');
let impressions = rivrAnalytics.context.queue.popAll();
if (impressions.length !== 0) {
let impressionsReq = Object.assign({}, {impressions});
@@ -111,7 +114,7 @@ function trackBidWon(args) {
function trackAuctionEnd(args) {
rivrAnalytics.context.auctionTimeEnd = Date.now();
- createEmptyBidResponses();
+ fillBidResponsesOfUnrespondedBidRequests();
};
function trackBidTimeout(args) {
@@ -189,7 +192,7 @@ function createBidResponse(bidResponseEvent) {
function createSingleEmptyBidResponse(bidResponse) {
return {
timestamp: bidResponse.start,
- total_duration: 'noResponseDuration',
+ total_duration: null,
bidderId: null,
bidder_name: bidResponse.bidder,
cur: null,
@@ -443,10 +446,12 @@ export function ExpiringQueue(sendImpressions, sendAuction, ttl, log) {
this.init = reset;
function reset() {
+ console.log('Function called: ============= reset');
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
+ console.log('Function called: ============= reset -> timeout expired');
sendAuction();
if (queue.length) {
sendImpressions();
@@ -467,15 +472,15 @@ function assignBidWonStatusToResponse(wonBid) {
});
};
-function createEmptyBidResponses() {
- let unRespondedBidRequests = findAllUnrespondedBidRequests();
+function fillBidResponsesOfUnrespondedBidRequests() {
+ let unRespondedBidRequests = getAllUnrespondedBidRequests();
unRespondedBidRequests.forEach((bid) => {
let emptyBidResponse = createSingleEmptyBidResponse(bid);
rivrAnalytics.context.auctionObject.bidResponses.push(emptyBidResponse);
});
};
-function findAllUnrespondedBidRequests() {
+function getAllUnrespondedBidRequests() {
let respondedBidIds = getAllRespondedBidIds();
let bidRequests = rivrAnalytics.context.auctionObject.bidRequests;
let allNotRespondedBidRequests = bidRequests.reduce((cache, requestBidder) => {
@@ -490,6 +495,13 @@ function getAllRespondedBidIds() {
return rivrAnalytics.context.auctionObject.bidResponses.map((response) => response.seatbid[0].bid[0].adid);
};
+function removeEmptyProperties(obj) {
+ Object.keys(obj).forEach(function(key) {
+ if (obj[key] && typeof obj[key] === 'object') removeEmptyProperties(obj[key])
+ else if (obj[key] == null) delete obj[key]
+ });
+};
+
// save the base class function
rivrAnalytics.originEnableAnalytics = rivrAnalytics.enableAnalytics;
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index c52711f6ee9..0a462563d02 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -1,4 +1,4 @@
-import analyticsAdapter, {ExpiringQueue} from 'modules/rivrAnalyticsAdapter';
+import analyticsAdapter, {ExpiringQueue, sendAuction} from 'modules/rivrAnalyticsAdapter';
import {expect} from 'chai';
import adaptermanager from 'src/adaptermanager';
import * as ajax from 'src/ajax';
@@ -264,6 +264,7 @@ describe('', () => {
events.emit(CONSTANTS.EVENTS.AUCTION_END, RESPONSE);
const responses = analyticsAdapter.context.auctionObject.bidResponses;
expect(responses.length).to.be.eql(3);
+ expect(responses[2].total_duration).to.be.eql(null);
})
it('should handle winning bid', () => {
@@ -335,5 +336,23 @@ describe('', () => {
expect(responsesAfterSend.length).to.be.eql(0);
expect(requestsAfterSend.length).to.be.eql(0);
});
+
+ describe('sendAuction', () => {
+ it('clears empty payload properties', () => {
+ analyticsAdapter.context.auctionObject.nullProperty = null;
+ analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
+
+ sendAuction();
+
+ // sendAuction is called automatically. This is the reason why we are testing the second call here.
+ // Understand how to avoid it and isolate the test.
+ expect(ajaxStub.getCall(1).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/(\w+)\/auctions/);
+
+ const payload = JSON.parse(ajaxStub.getCall(1).args[2]);
+
+ expect(payload.Auction.notNullProperty).to.be.equal('aValue');
+ expect(payload.nullProperty).to.be.equal(undefined);
+ });
+ });
});
});
From 849897f9ab5aba82d371efc80fc3af106d394e64 Mon Sep 17 00:00:00 2001
From: Alessandro Di Giovanni
Date: Mon, 17 Sep 2018 14:08:56 +0000
Subject: [PATCH 45/62] Merged in RVR-1883-Add-Basic-Access-Authentication
(pull request #17)
RVR-1883 Add Basic Access Authentication
* RVR-1914 - Rename functions
* RVR-1914 - Set default total_duration to null in bid response
* RVR-1883 - Use RIVR_CLIENT_AUTH_TOKEN global variable for Auth token
* RVR-1883 - Restore stub after every test not just at the end
* RVR-1883 - Remove commented code
---
modules/rivrAnalyticsAdapter.js | 60 ++++++++-------
.../spec/modules/rivrAnalyticsAdapter_spec.js | 77 ++++++++++++-------
2 files changed, 83 insertions(+), 54 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index ca64d4710bf..38e857f472a 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -51,44 +51,49 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
export function sendAuction() {
console.log('Function called: ============= sendAuction');
- removeEmptyProperties(rivrAnalytics.context.auctionObject)
- let auctionObject = rivrAnalytics.context.auctionObject;
- let req = Object.assign({}, {Auction: auctionObject});
- rivrAnalytics.context.auctionObject = fulfillAuctionObject();
- logInfo('sending request to analytics => ', req);
- ajax(
- `http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`,
- () => {},
- JSON.stringify(req),
- {
- contentType: 'application/json',
- customHeaders: {
- 'Authorization': 'Basic b3V0ZXJwYXNzaXZlOkQ3OVZ5YXI1eVZXUEVBaHI='
- }
- }
- );
-};
-
-function sendImpressions() {
- console.log('Function called: ============= sendImpressions');
- let impressions = rivrAnalytics.context.queue.popAll();
- if (impressions.length !== 0) {
- let impressionsReq = Object.assign({}, {impressions});
- logInfo('sending impressions request to analytics => ', impressionsReq);
+ console.log('Function called: ============= sendAuction rivrAnalytics.context.authToken', rivrAnalytics.context.authToken);
+ if (rivrAnalytics.context.authToken) {
+ removeEmptyProperties(rivrAnalytics.context.auctionObject)
+ let auctionObject = rivrAnalytics.context.auctionObject;
+ let req = Object.assign({}, {Auction: auctionObject});
+ rivrAnalytics.context.auctionObject = fulfillAuctionObject();
+ logInfo('sending request to analytics => ', req);
ajax(
- `http://${rivrAnalytics.context.host}/impressions`,
+ `http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`,
() => {},
- JSON.stringify(impressionsReq),
+ JSON.stringify(req),
{
contentType: 'application/json',
customHeaders: {
- 'Authorization': 'Basic b3V0ZXJwYXNzaXZlOkQ3OVZ5YXI1eVZXUEVBaHI='
+ 'Authorization': 'Basic ' + rivrAnalytics.context.authToken
}
}
);
}
};
+function sendImpressions() {
+ console.log('Function called: ============= sendImpressions');
+ if (rivrAnalytics.context.authToken) {
+ let impressions = rivrAnalytics.context.queue.popAll();
+ if (impressions.length !== 0) {
+ let impressionsReq = Object.assign({}, {impressions});
+ logInfo('sending impressions request to analytics => ', impressionsReq);
+ ajax(
+ `http://${rivrAnalytics.context.host}/impressions`,
+ () => {},
+ JSON.stringify(impressionsReq),
+ {
+ contentType: 'application/json',
+ customHeaders: {
+ 'Authorization': 'Basic ' + rivrAnalytics.context.authToken
+ }
+ }
+ );
+ }
+ }
+};
+
function trackAuctionInit(args) {
rivrAnalytics.context.auctionTimeStart = Date.now();
rivrAnalytics.context.auctionObject.id = args.auctionId;
@@ -518,6 +523,7 @@ rivrAnalytics.enableAnalytics = (config) => {
auctionObject: {},
adUnits: copiedUnits,
clientID: config.options.clientID,
+ authToken: config.options.authToken,
queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
let bannersIds = config.options.bannersIds
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 0a462563d02..98505c51228 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -133,11 +133,11 @@ describe('', () => {
let timer;
before(() => {
- ajaxStub = sandbox.stub(ajax, 'ajax');
timer = sandbox.useFakeTimers(0);
});
beforeEach(() => {
+ ajaxStub = sandbox.stub(ajax, 'ajax');
sandbox.stub(events, 'getEvents').callsFake(() => {
return []
});
@@ -145,6 +145,7 @@ describe('', () => {
afterEach(() => {
events.getEvents.restore();
+ ajaxStub.restore();
});
it('should be configurable', () => {
@@ -315,43 +316,65 @@ describe('', () => {
});
});
- it('sends request after timeout', () => {
- let impressions = analyticsAdapter.context.auctionObject.imp;
- let responses = analyticsAdapter.context.auctionObject.bidResponses;
- let requests = analyticsAdapter.context.auctionObject.bidRequests;
+ describe('when authToken is defined', () => {
+ it('sends request after timeout', () => {
+ analyticsAdapter.context.authToken = 'anAuthToken';
+ let impressions = analyticsAdapter.context.auctionObject.imp;
+ let responses = analyticsAdapter.context.auctionObject.bidResponses;
+ let requests = analyticsAdapter.context.auctionObject.bidRequests;
- expect(impressions.length).to.be.eql(1);
- expect(responses.length).to.be.eql(3);
- expect(requests.length).to.be.eql(3);
- expect(ajaxStub.calledOnce).to.be.equal(false);
+ expect(impressions.length).to.be.eql(1);
+ expect(responses.length).to.be.eql(3);
+ expect(requests.length).to.be.eql(3);
+ expect(ajaxStub.notCalled).to.be.equal(true);
- timer.tick(4500);
+ timer.tick(4500);
- let impressionsAfterSend = analyticsAdapter.context.auctionObject.imp;
- let responsesAfterSend = analyticsAdapter.context.auctionObject.bidResponses;
- let requestsAfterSend = analyticsAdapter.context.auctionObject.bidRequests;
+ let impressionsAfterSend = analyticsAdapter.context.auctionObject.imp;
+ let responsesAfterSend = analyticsAdapter.context.auctionObject.bidResponses;
+ let requestsAfterSend = analyticsAdapter.context.auctionObject.bidRequests;
- expect(ajaxStub.calledOnce).to.be.equal(true);
- expect(impressionsAfterSend.length).to.be.eql(0);
- expect(responsesAfterSend.length).to.be.eql(0);
- expect(requestsAfterSend.length).to.be.eql(0);
+ expect(ajaxStub.calledOnce).to.be.equal(true);
+ expect(impressionsAfterSend.length).to.be.eql(0);
+ expect(responsesAfterSend.length).to.be.eql(0);
+ expect(requestsAfterSend.length).to.be.eql(0);
+
+ analyticsAdapter.context.authToken = undefined;
+ });
});
describe('sendAuction', () => {
- it('clears empty payload properties', () => {
- analyticsAdapter.context.auctionObject.nullProperty = null;
- analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
+ describe('when authToken is defined', () => {
+ it('fires call clearing empty payload properties', () => {
+ analyticsAdapter.context.authToken = 'anAuthToken';
+ analyticsAdapter.context.auctionObject.nullProperty = null;
+ analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
+
+ sendAuction();
+
+ expect(ajaxStub.getCall(0).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/(\w+)\/auctions/);
+
+ const payload = JSON.parse(ajaxStub.getCall(0).args[2]);
+
+ expect(payload.Auction.notNullProperty).to.be.equal('aValue');
+ expect(payload.nullProperty).to.be.equal(undefined);
+
+ analyticsAdapter.context.authToken = undefined;
+ });
+ });
- sendAuction();
+ describe('when authToken is not defined', () => {
+ it('does not fire call', () => {
+ analyticsAdapter.context.authToken = undefined;
+ analyticsAdapter.context.auctionObject.nullProperty = null;
+ analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
- // sendAuction is called automatically. This is the reason why we are testing the second call here.
- // Understand how to avoid it and isolate the test.
- expect(ajaxStub.getCall(1).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/(\w+)\/auctions/);
+ expect(ajaxStub.callCount).to.be.equal(0);
- const payload = JSON.parse(ajaxStub.getCall(1).args[2]);
+ sendAuction();
- expect(payload.Auction.notNullProperty).to.be.equal('aValue');
- expect(payload.nullProperty).to.be.equal(undefined);
+ expect(ajaxStub.callCount).to.be.equal(0);
+ });
});
});
});
From 77e39d5ef425debee8e65b23c23b2354da1d4125 Mon Sep 17 00:00:00 2001
From: Alessandro Di Giovanni
Date: Mon, 1 Oct 2018 15:14:50 +0000
Subject: [PATCH 46/62] Increase code coverage
---
modules/rivrAnalyticsAdapter.js | 51 +-
.../spec/modules/rivrAnalyticsAdapter_spec.js | 872 ++++++++++++------
2 files changed, 621 insertions(+), 302 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 38e857f472a..846c8bd3250 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -17,6 +17,7 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
let handler = null;
switch (eventType) {
case CONSTANTS.EVENTS.AUCTION_INIT:
+ logInfo(`CONSTANTS.EVENTS.AUCTION_INIT rivrAnalytics.context.auctionObject`, rivrAnalytics.context.auctionObject);
if (rivrAnalytics.context.queue) {
rivrAnalytics.context.queue.init();
}
@@ -50,10 +51,8 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
});
export function sendAuction() {
- console.log('Function called: ============= sendAuction');
- console.log('Function called: ============= sendAuction rivrAnalytics.context.authToken', rivrAnalytics.context.authToken);
if (rivrAnalytics.context.authToken) {
- removeEmptyProperties(rivrAnalytics.context.auctionObject)
+ removeEmptyProperties(rivrAnalytics.context.auctionObject);
let auctionObject = rivrAnalytics.context.auctionObject;
let req = Object.assign({}, {Auction: auctionObject});
rivrAnalytics.context.auctionObject = fulfillAuctionObject();
@@ -62,6 +61,7 @@ export function sendAuction() {
`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`,
() => {},
JSON.stringify(req),
+ // TODO extract this object to variable
{
contentType: 'application/json',
customHeaders: {
@@ -72,8 +72,7 @@ export function sendAuction() {
}
};
-function sendImpressions() {
- console.log('Function called: ============= sendImpressions');
+export function sendImpressions() {
if (rivrAnalytics.context.authToken) {
let impressions = rivrAnalytics.context.queue.popAll();
if (impressions.length !== 0) {
@@ -141,20 +140,23 @@ function setCurrentPublisherId(bidRequested) {
}
};
-function fetchLocalization() {
+export function fetchLocalization() {
if (navigator.permissions) {
navigator.permissions.query({ name: 'geolocation' }).then((permission) => {
if (permission.status === 'granted') {
navigator.geolocation.getCurrentPosition((position) => {
- let deviceLocation = rivrAnalytics.context.auctionObject.device.geo;
- deviceLocation.lat = position.coords.latitude;
- deviceLocation.long = position.coords.longitude;
+ setAuctionAbjectPosition(position);
});
}
});
}
}
+export function setAuctionAbjectPosition(position) {
+ rivrAnalytics.context.auctionObject.device.geo.lat = position.coords.latitude;
+ rivrAnalytics.context.auctionObject.device.geo.long = position.coords.longitude;
+}
+
function getPlatformType() {
if (navigator.userAgent.match(/mobile/i)) {
return 'Mobile';
@@ -223,7 +225,7 @@ function createAuctionImpression(bidWonEvent) {
}
};
-function reportClickEvent(event) {
+export function reportClickEvent(event) {
let link = event.currentTarget.getElementsByTagName('a')[0];
let clickUrl;
if (link) {
@@ -237,6 +239,8 @@ function reportClickEvent(event) {
'click_url': clickUrl
};
logInfo('Sending click events with parameters: ', req);
+
+ // TODO add Authentication header
ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/clicks`, () => {
}, JSON.stringify(req));
};
@@ -249,7 +253,7 @@ function addDisplayedImpHandler(bannerId) {
pinHandlerToHTMLElement(bannerId, dataLoaderForHandler, impHandler);
};
-function pinHandlerToHTMLElement(elementId, dataLoaderForHandler, specializedHandler) {
+export function pinHandlerToHTMLElement(elementId, dataLoaderForHandler, specializedHandler) {
function waitForElement() {
let element = document.getElementById(elementId);
if (!element) {
@@ -261,7 +265,7 @@ function pinHandlerToHTMLElement(elementId, dataLoaderForHandler, specializedHan
waitForElement();
}
-function dataLoaderForHandler(element, specializedHandler) {
+export function dataLoaderForHandler(element, specializedHandler) {
function waitForElement() {
let iframe = element.getElementsByTagName('iframe')[0];
if (!iframe) {
@@ -363,7 +367,7 @@ function fulfillAuctionObject() {
'ext.rivr.optimiser': localStorage.getItem('rivr_should_optimise') || 'unoptimised',
modelVersion: localStorage.getItem('rivr_model_version') || null,
'ext.rivr.originalvalues': []
- }
+ };
return newAuction;
};
@@ -374,9 +378,9 @@ function saveUnoptimisedParams() {
let allUnits = connectAllUnits(units);
allUnits.forEach((adUnit) => {
adUnit.bids.forEach((bid) => {
- let configForAd = fetchConfigForBidder(bid.bidder);
- if (configForAd) {
- let unOptimisedParamsField = createUnOptimisedParamsField(bid, configForAd)
+ let configForBidder = fetchConfigForBidder(bid.bidder);
+ if (configForBidder) {
+ let unOptimisedParamsField = createUnOptimisedParamsField(bid, configForBidder);
rivrAnalytics.context.auctionObject['ext.rivr.originalvalues'].push(unOptimisedParamsField);
}
})
@@ -392,15 +396,15 @@ function connectAllUnits(units) {
}, []);
}
-function createUnOptimisedParamsField(unit, config) {
+export function createUnOptimisedParamsField(bid, config) {
let floorPriceLabel = config['floorPriceLabel'];
let currencyLabel = config['currencyLabel'];
let pmpLabel = config['pmpLabel'];
return {
- 'ext.rivr.demand_source_original': unit.bidder,
- 'ext.rivr.bidfloor_original': unit.params[floorPriceLabel],
- 'ext.rivr.currency_original': unit.params[currencyLabel],
- 'ext.rivr.pmp_original': unit.params[pmpLabel],
+ 'ext.rivr.demand_source_original': bid.bidder,
+ 'ext.rivr.bidfloor_original': bid.params[floorPriceLabel],
+ 'ext.rivr.currency_original': bid.params[currencyLabel],
+ 'ext.rivr.pmp_original': bid.params[pmpLabel],
}
}
@@ -451,12 +455,10 @@ export function ExpiringQueue(sendImpressions, sendAuction, ttl, log) {
this.init = reset;
function reset() {
- console.log('Function called: ============= reset');
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
- console.log('Function called: ============= reset -> timeout expired');
sendAuction();
if (queue.length) {
sendImpressions();
@@ -526,7 +528,8 @@ rivrAnalytics.enableAnalytics = (config) => {
authToken: config.options.authToken,
queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
};
- let bannersIds = config.options.bannersIds
+
+ let bannersIds = config.options.bannersIds;
if (bannersIds) {
if (bannersIds.length > 0) {
addHandlers(config.options.bannersIds);
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 98505c51228..dca63bf935e 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -1,4 +1,15 @@
-import analyticsAdapter, {ExpiringQueue, sendAuction} from 'modules/rivrAnalyticsAdapter';
+import * as utils from 'src/utils';
+import analyticsAdapter from 'modules/rivrAnalyticsAdapter';
+import {
+ ExpiringQueue,
+ sendAuction,
+ sendImpressions,
+ reportClickEvent,
+ createUnOptimisedParamsField,
+ dataLoaderForHandler,
+ pinHandlerToHTMLElement,
+ setAuctionAbjectPosition,
+} from 'modules/rivrAnalyticsAdapter';
import {expect} from 'chai';
import adaptermanager from 'src/adaptermanager';
import * as ajax from 'src/ajax';
@@ -6,50 +17,557 @@ import CONSTANTS from 'src/constants.json';
const events = require('../../../src/events');
-describe('', () => {
+describe('RIVR Analytics adapter', () => {
+ const EXPIRING_QUEUE_TIMEOUT = 4000;
+ const EXPIRING_QUEUE_TIMEOUT_MOCK = 100;
+ const PUBLISHER_ID_MOCK = 777;
+ const EMITTED_AUCTION_ID = 1;
+ const TRACKER_BASE_URL_MOCK = 'tracker.rivr.simplaex.com';
let sandbox;
+ let ajaxStub;
+ let timer;
before(() => {
sandbox = sinon.sandbox.create();
});
+ beforeEach(() => {
+ timer = sandbox.useFakeTimers(0);
+ ajaxStub = sandbox.stub(ajax, 'ajax');
+ sinon.stub(events, 'getEvents').returns([]);
+
+ adaptermanager.registerAnalyticsAdapter({
+ code: 'rivr',
+ adapter: analyticsAdapter
+ });
+ adaptermanager.enableAnalytics({
+ provider: 'rivr',
+ options: {
+ pubId: PUBLISHER_ID_MOCK,
+ adUnits: [utils.deepClone(AD_UNITS_MOCK)]
+ }
+ });
+ });
+
+ afterEach(() => {
+ analyticsAdapter.disableAnalytics();
+ events.getEvents.restore();
+ ajaxStub.restore();
+ timer.restore();
+ });
+
after(() => {
sandbox.restore();
- analyticsAdapter.disableAnalytics();
});
- describe('ExpiringQueue', () => {
- let timer;
- before(() => {
- timer = sandbox.useFakeTimers(0);
+ it('ExpiringQueue should call sendImpression callback after expiring queue timeout is elapsed', (done) => {
+ const sendImpressionMock = () => {
+ let elements = queue.popAll();
+ expect(elements).to.be.eql([1, 2, 3, 4]);
+ elements = queue.popAll();
+ expect(elements).to.have.lengthOf(0);
+ expect(Date.now()).to.be.equal(200);
+ done();
+ };
+ const sendAuctionMock = () => {};
+
+ let queue = new ExpiringQueue(
+ sendImpressionMock,
+ sendAuctionMock,
+ EXPIRING_QUEUE_TIMEOUT_MOCK);
+
+ queue.push(1);
+
+ setTimeout(() => {
+ queue.push([2, 3]);
+ timer.tick(50);
+ }, 50);
+ setTimeout(() => {
+ queue.push([4]);
+ timer.tick(100);
+ }, 100);
+ timer.tick(50);
+ });
+
+ it('enableAnalytics - should configure host and pubId in adapter context', () => {
+ // adaptermanager.enableAnalytics() is called in beforeEach. If only called here it doesn't seem to work.
+
+ expect(analyticsAdapter.context).to.have.property('host', TRACKER_BASE_URL_MOCK);
+ expect(analyticsAdapter.context).to.have.property('pubId', PUBLISHER_ID_MOCK);
+ });
+
+ it('Firing AUCTION_INIT should set auction id of context when AUCTION_INIT event is fired', () => {
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000});
+ const auctionId = analyticsAdapter.context.auctionObject.id;
+ expect(auctionId).to.be.eql(EMITTED_AUCTION_ID);
+ });
+
+ it('Firing AUCTION_INIT when rivr_should_optimise and rivr_model_version are in local storage, sets ext.rivr.optimiser and modelVersion of in auction context', () => {
+ const RIVR_SHOULD_OPTIMISE_VALUE_MOCK = 'optimise';
+ const RIVR_MODEL_VERSION_VALUE_MOCK = 'some model version';
+
+ localStorage.setItem('rivr_should_optimise', RIVR_SHOULD_OPTIMISE_VALUE_MOCK);
+ localStorage.setItem('rivr_model_version', RIVR_MODEL_VERSION_VALUE_MOCK);
+
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 2, config: {}, timeout: 3000});
+
+ let auctionObject2 = analyticsAdapter.context.auctionObject;
+
+ expect(auctionObject2['ext.rivr.optimiser']).to.be.eql(RIVR_SHOULD_OPTIMISE_VALUE_MOCK);
+ expect(auctionObject2['modelVersion']).to.be.eql(RIVR_MODEL_VERSION_VALUE_MOCK);
+
+ localStorage.removeItem('rivr_should_optimise');
+ localStorage.removeItem('rivr_model_version');
+ });
+
+ it('Firing AUCTION_INIT , when auction object is already there and rivr_config_string is not in local storage, it does not save unoptimized params in rivr original values', () => {
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 3, config: {}, timeout: 3000});
+
+ expect(analyticsAdapter.context.auctionObject['ext.rivr.originalvalues']).to.be.eql([]);
+ });
+
+ it('Firing AUCTION_INIT when rivr_should_optimise and rivr_model_version are NOT in local storage, does not set ext.rivr.optimiser and modelVersion of in auction context', () => {
+ localStorage.removeItem('rivr_should_optimise');
+ localStorage.removeItem('rivr_model_version');
+
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 3, config: {}, timeout: 3000});
+
+ let auctionObject3 = analyticsAdapter.context.auctionObject;
+
+ expect(auctionObject3['ext.rivr.optimiser']).to.be.eql('unoptimised');
+ expect(auctionObject3['modelVersion']).to.be.eql(null);
+ });
+
+ it('Firing BID_REQUESTED it sets app and site publisher id in auction object', () => {
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+
+ events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
+
+ const sitePubcid = analyticsAdapter.context.auctionObject.site.publisher.id;
+ const appPubcid = analyticsAdapter.context.auctionObject.app.publisher.id;
+ expect(sitePubcid).to.be.eql(PUBLISHER_ID_MOCK);
+ expect(appPubcid).to.be.eql(PUBLISHER_ID_MOCK);
+ });
+
+ it('Firing BID_REQUESTED it adds bid request in bid requests array', () => {
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+
+ events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
+
+ const requestEvent = analyticsAdapter.context.auctionObject.bidRequests;
+ expect(requestEvent).to.have.length(1);
+ expect(requestEvent[0]).to.be.eql({
+ bidderCode: 'adapter',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
+ bidderRequestId: '1a6fc81528d0f6',
+ bids: [{
+ bidder: 'adapter',
+ params: {},
+ adUnitCode: 'container-1',
+ transactionId: 'de90df62-7fd0-4fbc-8787-92d133a7dc06',
+ sizes: [[300, 250]],
+ bidId: '208750227436c1',
+ bidderRequestId: '1a6fc81528d0f6',
+ auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f'
+ }],
+ auctionStart: 1509369418387,
+ timeout: 3000,
+ start: 1509369418389
});
- after(() => {
- timer.restore();
+ });
+
+ it('Firing BID_RESPONSE it inserts bid response object in auctionObject', () => {
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+
+ events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
+ const bidResponses = analyticsAdapter.context.auctionObject.bidResponses;
+
+ expect(bidResponses).to.have.length(1);
+ expect(bidResponses[0]).to.be.eql({
+ timestamp: 1509369418832,
+ status: 1,
+ 'total_duration': 443,
+ bidderId: null,
+ 'bidder_name': 'adapter',
+ cur: 'EU',
+ seatbid: [
+ {
+ seat: null,
+ bid: [
+ {
+ status: 2,
+ 'clear_price': 0.015,
+ attr: [],
+ crid: 999,
+ cid: null,
+ id: null,
+ adid: '208750227436c1',
+ adomain: [],
+ iurl: null
+ }
+ ]
+ }
+ ]
});
+ });
- it('should notify after timeout period', (done) => {
- let queue = new ExpiringQueue(() => {
- let elements = queue.popAll();
- expect(elements).to.be.eql([1, 2, 3, 4]);
- elements = queue.popAll();
- expect(elements).to.have.lengthOf(0);
- expect(Date.now()).to.be.equal(200);
- done();
- }, () => {}, 100);
-
- queue.push(1);
- setTimeout(() => {
- queue.push([2, 3]);
- timer.tick(50);
- }, 50);
- setTimeout(() => {
- queue.push([4]);
- timer.tick(100);
- }, 100);
- timer.tick(50);
+ it('Firing AUCTION_END it sets auction time end to current time', () => {
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+
+ const MILLIS_FROM_EPOCH_TO_NOW_MOCK = 477;
+ timer.tick(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
+
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, BID_RESPONSE_MOCK);
+
+ const endTime = analyticsAdapter.context.auctionTimeEnd;
+ expect(endTime).to.be.eql(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
+ });
+
+ it('Firing AUCTION_END when there are unresponded bid requests should insert then to bidResponses in auctionObject with null duration', () => {
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+
+ events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST2);
+ events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST3);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, BID_RESPONSE_MOCK);
+
+ const responses = analyticsAdapter.context.auctionObject.bidResponses;
+ expect(responses.length).to.be.eql(2);
+ expect(responses[0].total_duration).to.be.eql(null);
+ expect(responses[1].total_duration).to.be.eql(null);
+ });
+
+ it('Firing BID_WON when it happens after BID_RESPONSE should add won event as auction impression to imp array', () => {
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+
+ events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
+ events.emit(CONSTANTS.EVENTS.BID_WON, BID_RESPONSE_MOCK);
+
+ const wonEvent = analyticsAdapter.context.auctionObject.imp;
+
+ expect(wonEvent.length).to.be.eql(1);
+ expect(wonEvent[0]).to.be.eql({
+ tagid: 'container-1',
+ displaymanager: null,
+ displaymanagerver: null,
+ secure: null,
+ bidfloor: null,
+ banner: {
+ w: 300,
+ h: 250,
+ pos: null,
+ expandable: [],
+ api: []
+ }
});
});
+ it('Firing BID_WON when it happens after BID_RESPONSE should change the status of winning bidResponse to 1', () => {
+ const BID_STATUS_WON = 1;
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+
+ events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
+ events.emit(CONSTANTS.EVENTS.BID_WON, BID_RESPONSE_MOCK);
+
+ const responseWhichIsWonAlso = analyticsAdapter.context.auctionObject.bidResponses[0];
+
+ expect(responseWhichIsWonAlso.seatbid[0].bid[0].status).to.be.eql(BID_STATUS_WON);
+ });
+
+ it('when auction is initialized and authToken is defined and ExpiringQueue ttl expires, it sends the auction', () => {
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000});
+ analyticsAdapter.context.authToken = 'anAuthToken';
+
+ expect(ajaxStub.notCalled).to.be.equal(true);
+
+ timer.tick(EXPIRING_QUEUE_TIMEOUT + 500);
+
+ expect(ajaxStub.calledOnce).to.be.equal(true);
+ });
+
+ it('when auction is initialized and authToken is defined and ExpiringQueue ttl expires, it clears imp, bidResponses and bidRequests', () => {
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000});
+
+ analyticsAdapter.context.authToken = 'anAuthToken';
+ events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
+ events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
+ events.emit(CONSTANTS.EVENTS.BID_WON, BID_RESPONSE_MOCK);
+
+ let impressions = analyticsAdapter.context.auctionObject.imp;
+ let responses = analyticsAdapter.context.auctionObject.bidResponses;
+ let requests = analyticsAdapter.context.auctionObject.bidRequests;
+
+ expect(impressions.length).to.be.eql(1);
+ expect(responses.length).to.be.eql(1);
+ expect(requests.length).to.be.eql(1);
+
+ timer.tick(EXPIRING_QUEUE_TIMEOUT + 500);
+
+ let impressionsAfterSend = analyticsAdapter.context.auctionObject.imp;
+ let responsesAfterSend = analyticsAdapter.context.auctionObject.bidResponses;
+ let requestsAfterSend = analyticsAdapter.context.auctionObject.bidRequests;
+
+ expect(impressionsAfterSend.length).to.be.eql(0);
+ expect(responsesAfterSend.length).to.be.eql(0);
+ expect(requestsAfterSend.length).to.be.eql(0);
+ });
+
+ it('sendAuction(), when authToken is defined, it fires call clearing empty payload properties', () => {
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+ analyticsAdapter.context.authToken = 'anAuthToken';
+ analyticsAdapter.context.auctionObject.nullProperty = null;
+ analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
+
+ sendAuction();
+
+ expect(ajaxStub.getCall(0).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/(\w+)\/auctions/);
+
+ const payload = JSON.parse(ajaxStub.getCall(0).args[2]);
+
+ expect(payload.Auction.notNullProperty).to.be.equal('aValue');
+ expect(payload.nullProperty).to.be.equal(undefined);
+
+ analyticsAdapter.context.authToken = undefined;
+ });
+
+ it('sendAuction(), when authToken is not defined, it does not fire call', () => {
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+ analyticsAdapter.context.authToken = undefined;
+ analyticsAdapter.context.auctionObject.nullProperty = null;
+ analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
+
+ expect(ajaxStub.callCount).to.be.equal(0);
+
+ sendAuction();
+
+ expect(ajaxStub.callCount).to.be.equal(0);
+ });
+
+ it('sendImpressions(), when authToken is not defined, it does not fire call', () => {
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+ analyticsAdapter.context.authToken = undefined;
+ analyticsAdapter.context.auctionObject.nullProperty = null;
+ analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
+
+ expect(ajaxStub.callCount).to.be.equal(0);
+
+ sendImpressions();
+
+ expect(ajaxStub.callCount).to.be.equal(0);
+ });
+
+ it('sendImpressions(), when authToken is defined and there are impressions, it sends impressions to the tracker', () => {
+ const aMockString = 'anImpressionPropertyValue';
+ const IMPRESSION_MOCK = { anImpressionProperty: aMockString };
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+ analyticsAdapter.context.authToken = 'anAuthToken';
+ analyticsAdapter.context.queue = new ExpiringQueue(
+ () => {},
+ () => {},
+ EXPIRING_QUEUE_TIMEOUT_MOCK
+ );
+
+ analyticsAdapter.context.queue.push(IMPRESSION_MOCK);
+
+ expect(ajaxStub.callCount).to.be.equal(0);
+
+ sendImpressions();
+
+ const payload = JSON.parse(ajaxStub.getCall(0).args[2]);
+
+ expect(ajaxStub.callCount).to.be.equal(1);
+ expect(payload.impressions.length).to.be.equal(1);
+ expect(ajaxStub.getCall(0).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/impressions/);
+ expect(payload.impressions[0].anImpressionProperty).to.be.equal(aMockString);
+ });
+
+ it('reportClickEvent(), when authToken is not defined, it calls endpoint', () => {
+ const CLIENT_ID_MOCK = 'aClientId';
+ const CLICK_URL_MOCK = 'clickURLMock';
+ const EVENT_MOCK = {
+ currentTarget: {
+ getElementsByTagName: () => {
+ return [
+ {
+ getAttribute: (attributeName) => {
+ return CLICK_URL_MOCK;
+ }
+ }
+ ]
+ }
+ }
+ };
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+ analyticsAdapter.context.authToken = undefined;
+ analyticsAdapter.context.clientID = CLIENT_ID_MOCK;
+ analyticsAdapter.context.auctionObject.nullProperty = null;
+ analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
+
+ expect(ajaxStub.callCount).to.be.equal(0);
+
+ reportClickEvent(EVENT_MOCK);
+
+ const payload = JSON.parse(ajaxStub.getCall(0).args[2]);
+
+ expect(ajaxStub.callCount).to.be.equal(1);
+ expect(ajaxStub.getCall(0).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/aClientId\/clicks/);
+ expect(payload.timestamp).to.be.equal('1970-01-01T00:00:00.000Z');
+ expect(payload.request_id).to.be.a('string');
+ expect(payload.click_url).to.be.equal(CLICK_URL_MOCK);
+ });
+
+ it('createUnOptimisedParamsField(), creates object with unoptimized properties', () => {
+ const CONFIG_FOR_BIDDER_MOCK = {
+ floorPriceLabel: 'floorPriceLabelForTestBidder',
+ currencyLabel: 'currencyLabelForTestBidder',
+ pmpLabel: 'pmpLabelForTestBidder',
+ };
+ const BID_MOCK = {
+ bidder: 'aBidder',
+ params: {
+ floorPriceLabelForTestBidder: 'theOriginalBidFloor',
+ currencyLabelForTestBidder: 'theOriginalCurrency',
+ pmpLabelForTestBidder: 'theOriginalPmp',
+ },
+ };
+
+ const result = createUnOptimisedParamsField(BID_MOCK, CONFIG_FOR_BIDDER_MOCK);
+
+ expect(result['ext.rivr.demand_source_original']).to.be.equal('aBidder');
+ expect(result['ext.rivr.bidfloor_original']).to.be.equal('theOriginalBidFloor');
+ expect(result['ext.rivr.currency_original']).to.be.equal('theOriginalCurrency');
+ expect(result['ext.rivr.pmp_original']).to.be.equal('theOriginalPmp');
+ });
+
+ it('dataLoaderForHandler(), when iframe and the ad image contained in it are there, it calls the specialized handler', () => {
+ const MOCK_ELEMENT = {
+ getElementsByTagName: () => {
+ return [
+ {
+ contentDocument: {
+ getElementsByTagName: () => {
+ return ['displayedImpressionMock']
+ }
+ },
+ aDummyProperty: 'aDummyPropertyValue'
+ }
+ ]
+ }
+ };
+
+ var specializedHandlerSpy = sinon.spy();
+
+ expect(specializedHandlerSpy.callCount).to.be.equal(0);
+
+ dataLoaderForHandler(MOCK_ELEMENT, specializedHandlerSpy);
+
+ expect(specializedHandlerSpy.callCount).to.be.equal(1);
+ expect(specializedHandlerSpy.firstCall.args[0].aDummyProperty).to.be.equal('aDummyPropertyValue');
+ expect(specializedHandlerSpy.firstCall.args[0].contentDocument.getElementsByTagName()[0]).to.be.equal('displayedImpressionMock');
+ });
+
+ it('dataLoaderForHandler(), when iframe is not there, it requests animation frame', () => {
+ const MOCK_ELEMENT = {
+ getElementsByTagName: () => {
+ return [
+ {
+ contentDocument: {
+ getElementsByTagName: () => {
+ return []
+ }
+ },
+ }
+ ]
+ }
+ };
+
+ const specializedHandlerSpy = sinon.spy();
+ const requestAnimationFrameStub = sinon.stub(window, 'requestAnimationFrame');
+ expect(requestAnimationFrameStub.callCount).to.be.equal(0);
+
+ dataLoaderForHandler(MOCK_ELEMENT, specializedHandlerSpy);
+
+ expect(requestAnimationFrameStub.callCount).to.be.equal(1);
+
+ requestAnimationFrameStub.restore();
+ });
+
+ it('pinHandlerToHTMLElement(), when element is there, it calls dataLoaderForHandler', () => {
+ const ELEMENT_MOCK = {
+ anElementProperty: 'aValue'
+ }
+ const dataLoaderForHandlerSpy = sinon.spy();
+ sinon.stub(window, 'requestAnimationFrame');
+
+ sinon.stub(document, 'getElementById').returns(ELEMENT_MOCK);
+
+ expect(dataLoaderForHandlerSpy.callCount).to.be.equal(0);
+
+ pinHandlerToHTMLElement('', dataLoaderForHandlerSpy, () => {});
+
+ expect(dataLoaderForHandlerSpy.callCount).to.be.equal(1);
+ expect(dataLoaderForHandlerSpy.firstCall.args[0].anElementProperty).to.be.equal('aValue');
+
+ window.requestAnimationFrame.restore();
+ document.getElementById.restore();
+ });
+
+ it('pinHandlerToHTMLElement(), when element is not there, it requests animation frame', () => {
+ const dataLoaderForHandlerSpy = sinon.spy();
+ const requestAnimationFrameStub = sinon.stub(window, 'requestAnimationFrame');
+
+ sinon.stub(document, 'getElementById').returns(undefined);
+
+ expect(requestAnimationFrameStub.callCount).to.be.equal(0);
+
+ pinHandlerToHTMLElement('', dataLoaderForHandlerSpy, () => {});
+
+ expect(dataLoaderForHandlerSpy.callCount).to.be.equal(0);
+ expect(requestAnimationFrameStub.callCount).to.be.equal(1);
+
+ requestAnimationFrameStub.restore();
+ document.getElementById.restore();
+ });
+
+ it('setAuctionAbjectPosition(), it sets latitude and longitude in auction object', () => {
+ const POSITION_MOCK = {
+ coords: {
+ latitude: 'aLatitude',
+ longitude: 'aLongitude',
+ }
+ }
+ analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+
+ setAuctionAbjectPosition(POSITION_MOCK);
+
+ expect(analyticsAdapter.context.auctionObject.device.geo.lat).to.be.equal('aLatitude');
+ });
+
+ const AD_UNITS_MOCK = [
+ {
+ code: 'banner-container1',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 200], [300, 600]]
+ }
+ },
+ bids: [
+ {
+ bidder: 'appnexus',
+ params: {
+ placementId: '10433394',
+ reserve: 0.5
+ }
+ },
+ {
+ bidder: 'huddledmasses',
+ params: {
+ placement_id: 0
+ }
+ },
+ ]
+ }
+ ];
+
const REQUEST = {
bidderCode: 'adapter',
auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
@@ -107,7 +625,7 @@ describe('', () => {
start: 1509369418389
};
- const RESPONSE = {
+ const BID_RESPONSE_MOCK = {
bidderCode: 'adapter',
width: 300,
height: 250,
@@ -128,254 +646,52 @@ describe('', () => {
size: '300x250'
};
- describe('Analytics adapter', () => {
- let ajaxStub;
- let timer;
-
- before(() => {
- timer = sandbox.useFakeTimers(0);
- });
-
- beforeEach(() => {
- ajaxStub = sandbox.stub(ajax, 'ajax');
- sandbox.stub(events, 'getEvents').callsFake(() => {
- return []
- });
- });
-
- afterEach(() => {
- events.getEvents.restore();
- ajaxStub.restore();
- });
-
- it('should be configurable', () => {
- adaptermanager.registerAnalyticsAdapter({
- code: 'rivr',
- adapter: analyticsAdapter
- });
-
- adaptermanager.enableAnalytics({
- provider: 'rivr',
- options: {
- pubId: 777,
+ const CONTEXT_AFTER_AUCTION_INIT = {
+ host: TRACKER_BASE_URL_MOCK,
+ pubId: PUBLISHER_ID_MOCK,
+ queue: {
+ mockProp: 'mockValue'
+ },
+ auctionObject: {
+ id: null,
+ timestamp: null,
+ at: null,
+ bcat: [],
+ imp: [],
+ app: {
+ id: null,
+ name: null,
+ domain: window.location.href,
+ bundle: null,
+ cat: [],
+ publisher: {
+ id: null,
+ name: null
}
- });
-
- expect(analyticsAdapter.context).to.have.property('host', 'tracker.rivr.simplaex.com');
- expect(analyticsAdapter.context).to.have.property('pubId', 777);
- });
-
- it('should handle auction init event', () => {
- events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 1, config: {}, timeout: 3000});
- const auctionId = analyticsAdapter.context.auctionObject.id;
- const auctionStart = analyticsAdapter.context.auctionTimeStart;
- expect(auctionId).to.be.eql(1);
- });
-
- it('should map proper response params on auction init', () => {
- localStorage.setItem('rivr_should_optimise', 'optimise')
- localStorage.setItem('rivr_model_version', 'some model version');
- events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 2, config: {}, timeout: 3000});
- let auctionObject2 = analyticsAdapter.context.auctionObject;
-
- expect(auctionObject2['ext.rivr.optimiser']).to.be.eql('optimise');
- expect(auctionObject2['modelVersion']).to.be.eql('some model version');
-
- localStorage.removeItem('rivr_should_optimise');
- localStorage.removeItem('rivr_model_version');
-
- events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 3, config: {}, timeout: 3000});
-
- let auctionObject3 = analyticsAdapter.context.auctionObject;
-
- expect(auctionObject3['ext.rivr.optimiser']).to.be.eql('unoptimised');
- expect(auctionObject3['modelVersion']).to.be.eql(null);
- })
-
- it('should handle bid request event', () => {
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
- const sitePubcid = analyticsAdapter.context.auctionObject.site.publisher.id;
- const appPubcid = analyticsAdapter.context.auctionObject.app.publisher.id;
- const requestEvent = analyticsAdapter.context.auctionObject.bidRequests;
- expect(sitePubcid).to.be.eql(777);
- expect(sitePubcid).to.be.eql(appPubcid);
- expect(requestEvent).to.have.length(1);
- expect(requestEvent[0]).to.be.eql({
- bidderCode: 'adapter',
- auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
- bidderRequestId: '1a6fc81528d0f6',
- bids: [{
- bidder: 'adapter',
- params: {},
- adUnitCode: 'container-1',
- transactionId: 'de90df62-7fd0-4fbc-8787-92d133a7dc06',
- sizes: [[300, 250]],
- bidId: '208750227436c1',
- bidderRequestId: '1a6fc81528d0f6',
- auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f'
- }],
- auctionStart: 1509369418387,
- timeout: 3000,
- start: 1509369418389
- });
- });
-
- it('should handle bid response event', () => {
- events.emit(CONSTANTS.EVENTS.BID_RESPONSE, RESPONSE);
- const responseEvent = analyticsAdapter.context.auctionObject.bidResponses;
- expect(responseEvent).to.have.length(1);
- expect(responseEvent[0]).to.be.eql({
- timestamp: 1509369418832,
- status: 1,
- 'total_duration': 443,
- bidderId: null,
- 'bidder_name': 'adapter',
- cur: 'EU',
- seatbid: [
- {
- seat: null,
- bid: [
- {
- status: 2,
- 'clear_price': 0.015,
- attr: [],
- crid: 999,
- cid: null,
- id: null,
- adid: '208750227436c1',
- adomain: [],
- iurl: null
- }
- ]
- }
- ]
- });
- });
-
- it('should handle auction end event', () => {
- timer.tick(447);
- events.emit(CONSTANTS.EVENTS.AUCTION_END, RESPONSE);
- const endTime = analyticsAdapter.context.auctionTimeEnd;
- expect(endTime).to.be.eql(447);
- });
-
- it('should map unresponded requests to empty responded on auction end', () => {
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST2);
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST3);
- events.emit(CONSTANTS.EVENTS.AUCTION_END, RESPONSE);
- const responses = analyticsAdapter.context.auctionObject.bidResponses;
- expect(responses.length).to.be.eql(3);
- expect(responses[2].total_duration).to.be.eql(null);
- })
-
- it('should handle winning bid', () => {
- events.emit(CONSTANTS.EVENTS.BID_WON, RESPONSE);
- const responseWhichIsWonAlso = analyticsAdapter.context.auctionObject.bidResponses[0];
- const wonEvent = analyticsAdapter.context.auctionObject.imp;
- expect(wonEvent.length).to.be.eql(1);
- expect(wonEvent[0]).to.be.eql({
- tagid: 'container-1',
- displaymanager: null,
- displaymanagerver: null,
- secure: null,
- bidfloor: null,
- banner: {
- w: 300,
- h: 250,
- pos: null,
- expandable: [],
- api: []
+ },
+ site: {
+ id: null,
+ name: null,
+ domain: window.location.href,
+ cat: [],
+ publisher: {
+ id: null,
+ name: null
}
- });
-
- expect(responseWhichIsWonAlso).to.be.eql({
- timestamp: 1509369418832,
- status: 1,
- 'total_duration': 443,
- bidderId: null,
- 'bidder_name': 'adapter',
- cur: 'EU',
- seatbid: [
- {
- seat: null,
- bid: [
- {
- status: 1,
- 'clear_price': 0.015,
- attr: [],
- crid: 999,
- cid: null,
- id: null,
- adid: '208750227436c1',
- adomain: [],
- iurl: null
- }
- ]
- }
- ]
- });
- });
-
- describe('when authToken is defined', () => {
- it('sends request after timeout', () => {
- analyticsAdapter.context.authToken = 'anAuthToken';
- let impressions = analyticsAdapter.context.auctionObject.imp;
- let responses = analyticsAdapter.context.auctionObject.bidResponses;
- let requests = analyticsAdapter.context.auctionObject.bidRequests;
-
- expect(impressions.length).to.be.eql(1);
- expect(responses.length).to.be.eql(3);
- expect(requests.length).to.be.eql(3);
- expect(ajaxStub.notCalled).to.be.equal(true);
-
- timer.tick(4500);
-
- let impressionsAfterSend = analyticsAdapter.context.auctionObject.imp;
- let responsesAfterSend = analyticsAdapter.context.auctionObject.bidResponses;
- let requestsAfterSend = analyticsAdapter.context.auctionObject.bidRequests;
-
- expect(ajaxStub.calledOnce).to.be.equal(true);
- expect(impressionsAfterSend.length).to.be.eql(0);
- expect(responsesAfterSend.length).to.be.eql(0);
- expect(requestsAfterSend.length).to.be.eql(0);
-
- analyticsAdapter.context.authToken = undefined;
- });
- });
-
- describe('sendAuction', () => {
- describe('when authToken is defined', () => {
- it('fires call clearing empty payload properties', () => {
- analyticsAdapter.context.authToken = 'anAuthToken';
- analyticsAdapter.context.auctionObject.nullProperty = null;
- analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
-
- sendAuction();
-
- expect(ajaxStub.getCall(0).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/(\w+)\/auctions/);
-
- const payload = JSON.parse(ajaxStub.getCall(0).args[2]);
-
- expect(payload.Auction.notNullProperty).to.be.equal('aValue');
- expect(payload.nullProperty).to.be.equal(undefined);
-
- analyticsAdapter.context.authToken = undefined;
- });
- });
-
- describe('when authToken is not defined', () => {
- it('does not fire call', () => {
- analyticsAdapter.context.authToken = undefined;
- analyticsAdapter.context.auctionObject.nullProperty = null;
- analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
-
- expect(ajaxStub.callCount).to.be.equal(0);
-
- sendAuction();
-
- expect(ajaxStub.callCount).to.be.equal(0);
- });
- });
- });
- });
+ },
+ device: {
+ geo: {}
+ },
+ user: {
+ id: null,
+ yob: null,
+ gender: null,
+ },
+ bidResponses: [],
+ bidRequests: [],
+ 'ext.rivr.optimiser': 'unoptimised',
+ modelVersion: null,
+ 'ext.rivr.originalvalues': []
+ }
+ };
});
From 4ca7c57f337659aa94d0922a64ede1486b8e7aa1 Mon Sep 17 00:00:00 2001
From: adg
Date: Wed, 17 Oct 2018 16:39:29 +0200
Subject: [PATCH 47/62] Fix for IE 11.0.0 and Safari 8.0.8 - includes()
Use core-js includes function for array
---
modules/rivrAnalyticsAdapter.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 846c8bd3250..6dfe8f6b2c2 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -1,4 +1,5 @@
import {ajax} from 'src/ajax';
+import includes from 'core-js/library/fn/array/includes';
import adapter from 'src/AnalyticsAdapter';
import CONSTANTS from 'src/constants.json';
import adaptermanager from 'src/adaptermanager';
@@ -491,7 +492,7 @@ function getAllUnrespondedBidRequests() {
let respondedBidIds = getAllRespondedBidIds();
let bidRequests = rivrAnalytics.context.auctionObject.bidRequests;
let allNotRespondedBidRequests = bidRequests.reduce((cache, requestBidder) => {
- let notRespondedBids = requestBidder.bids.filter((bid) => !respondedBidIds.includes(bid.bidId));
+ let notRespondedBids = requestBidder.bids.filter((bid) => !includes(respondedBidIds, bid.bidId));
notRespondedBids.forEach((bid) => bid.start = requestBidder.start);
return cache.concat(notRespondedBids);
}, []);
From 099fe28b5494addcf800f33fd948aa0d013ce3b0 Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 19 Oct 2018 14:25:31 +0200
Subject: [PATCH 48/62] Restore pbjs_api_spec.js
---
test/spec/unit/pbjs_api_spec.js | 254 --------------------------------
1 file changed, 254 deletions(-)
diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js
index 144cbb656db..a03339c76b3 100644
--- a/test/spec/unit/pbjs_api_spec.js
+++ b/test/spec/unit/pbjs_api_spec.js
@@ -763,260 +763,6 @@ describe('Unit: Prebid Module', function () {
});
});
- describe('getAdserverTargeting with `mediaTypePriceGranularity` set for media type', function() {
- let currentPriceBucket;
- let auction;
- let ajaxStub;
- let response;
- let cbTimeout = 3000;
- let auctionManagerInstance;
- let targeting;
-
- const bannerResponse = {
- 'version': '0.0.1',
- 'tags': [{
- 'uuid': '4d0a6829338a07',
- 'tag_id': 4799418,
- 'auction_id': '2256922143947979797',
- 'no_ad_url': 'http://lax1-ib.adnxs.com/no-ad',
- 'timeout_ms': 2500,
- 'ads': [{
- 'content_source': 'rtb',
- 'ad_type': 'banner',
- 'buyer_member_id': 958,
- 'creative_id': 33989846,
- 'media_type_id': 1,
- 'media_subtype_id': 1,
- 'cpm': 1.99,
- 'cpm_publisher_currency': 0.500000,
- 'publisher_currency_code': '$',
- 'client_initiated_ad_counting': true,
- 'rtb': {
- 'banner': {
- 'width': 300,
- 'height': 250,
- 'content': ''
- },
- 'trackers': [{
- 'impression_urls': ['http://lax1-ib.adnxs.com/impression']
- }]
- }
- }]
- }]
- };
- const videoResponse = {
- 'version': '0.0.1',
- 'tags': [{
- 'uuid': '4d0a6829338a07',
- 'tag_id': 4799418,
- 'auction_id': '2256922143947979797',
- 'no_ad_url': 'http://lax1-ib.adnxs.com/no-ad',
- 'timeout_ms': 2500,
- 'ads': [{
- 'content_source': 'rtb',
- 'ad_type': 'video',
- 'buyer_member_id': 958,
- 'creative_id': 33989846,
- 'media_type_id': 1,
- 'media_subtype_id': 1,
- 'cpm': 1.99,
- 'cpm_publisher_currency': 0.500000,
- 'publisher_currency_code': '$',
- 'client_initiated_ad_counting': true,
- 'rtb': {
- 'video': {
- 'width': 300,
- 'height': 250,
- 'content': ''
- },
- 'trackers': [{
- 'impression_urls': ['http://lax1-ib.adnxs.com/impression']
- }]
- }
- }]
- }]
- };
-
- const createAdUnit = (code, mediaTypes) => {
- if (!mediaTypes) {
- mediaTypes = ['banner'];
- } else if (typeof mediaTypes === 'string') {
- mediaTypes = [mediaTypes];
- }
-
- const adUnit = {
- code: code,
- sizes: [[300, 250], [300, 600]],
- bids: [{
- bidder: 'appnexus',
- params: {
- placementId: '10433394'
- }
- }]
- };
-
- let _mediaTypes = {};
- if (mediaTypes.indexOf('banner') !== -1) {
- _mediaTypes['banner'] = {
- 'banner': {}
- };
- }
- if (mediaTypes.indexOf('video') !== -1) {
- _mediaTypes['video'] = {
- 'video': {
- context: 'instream',
- playerSize: [300, 250]
- }
- };
- }
- if (mediaTypes.indexOf('native') !== -1) {
- _mediaTypes['native'] = {
- 'native': {}
- };
- }
-
- if (Object.keys(_mediaTypes).length > 0) {
- adUnit['mediaTypes'] = _mediaTypes;
- // if video type, add video to every bid.param object
- if (_mediaTypes.video) {
- adUnit.bids.forEach(bid => {
- bid.params['video'] = {
- width: 300,
- height: 250,
- vastUrl: '',
- ttl: 3600
- };
- });
- }
- }
- return adUnit;
- }
- const initTestConfig = (data) => {
- $$PREBID_GLOBAL$$.bidderSettings = {};
-
- ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(function() {
- return function(url, callback) {
- const fakeResponse = sinon.stub();
- fakeResponse.returns('headerContent');
- callback.success(JSON.stringify(response), { getResponseHeader: fakeResponse });
- }
- });
- auctionManagerInstance = newAuctionManager();
- targeting = newTargeting(auctionManagerInstance)
-
- configObj.setConfig({
- 'priceGranularity': {
- 'buckets': [
- { 'precision': 2, 'min': 0, 'max': 5, 'increment': 0.01 },
- { 'precision': 2, 'min': 5, 'max': 8, 'increment': 0.05 },
- { 'precision': 2, 'min': 8, 'max': 20, 'increment': 0.5 },
- { 'precision': 2, 'min': 20, 'max': 25, 'increment': 1 }
- ]
- },
- 'mediaTypePriceGranularity': {
- 'banner': {
- 'buckets': [
- { 'precision': 2, 'min': 0, 'max': 5, 'increment': 0.25 },
- { 'precision': 2, 'min': 6, 'max': 20, 'increment': 0.5 },
- { 'precision': 2, 'min': 21, 'max': 100, 'increment': 1 }
- ]
- },
- 'video': 'low',
- 'native': 'high'
- }
- });
-
- auction = auctionManagerInstance.createAuction({
- adUnits: data.adUnits,
- adUnitCodes: data.adUnitCodes
- });
- };
-
- before(() => {
- currentPriceBucket = configObj.getConfig('priceGranularity');
- sinon.stub(adaptermanager, 'makeBidRequests').callsFake(() => ([{
- 'bidderCode': 'appnexus',
- 'auctionId': '20882439e3238c',
- 'bidderRequestId': '331f3cf3f1d9c8',
- 'bids': [
- {
- 'bidder': 'appnexus',
- 'params': {
- 'placementId': '10433394'
- },
- 'adUnitCode': 'div-gpt-ad-1460505748561-0',
- 'sizes': [
- [
- 300,
- 250
- ],
- [
- 300,
- 600
- ]
- ],
- 'bidId': '4d0a6829338a07',
- 'bidderRequestId': '331f3cf3f1d9c8',
- 'auctionId': '20882439e3238c'
- }
- ],
- 'auctionStart': 1505250713622,
- 'timeout': 3000
- }]));
- });
-
- after(() => {
- configObj.setConfig({ priceGranularity: currentPriceBucket });
- adaptermanager.makeBidRequests.restore();
- })
-
- afterEach(() => {
- ajaxStub.restore();
- });
-
- it('should get correct hb_pb with cpm between 0 - 5', () => {
- initTestConfig({
- adUnits: [createAdUnit('div-gpt-ad-1460505748561-0')],
- adUnitCodes: ['div-gpt-ad-1460505748561-0']
- });
-
- response = bannerResponse;
- response.tags[0].ads[0].cpm = 3.4288;
-
- auction.callBids(cbTimeout);
- let bidTargeting = targeting.getAllTargeting();
- expect(bidTargeting['div-gpt-ad-1460505748561-0']['hb_pb']).to.equal('3.25');
- });
-
- it('should get correct hb_pb with cpm between 21 - 100', () => {
- initTestConfig({
- adUnits: [createAdUnit('div-gpt-ad-1460505748561-0')],
- adUnitCodes: ['div-gpt-ad-1460505748561-0']
- });
-
- response = bannerResponse;
- response.tags[0].ads[0].cpm = 43.4288;
-
- auction.callBids(cbTimeout);
- let bidTargeting = targeting.getAllTargeting();
- expect(bidTargeting['div-gpt-ad-1460505748561-0']['hb_pb']).to.equal('43.00');
- });
-
- it('should only apply price granularity if bid media type matches', () => {
- initTestConfig({
- adUnits: [ createAdUnit('div-gpt-ad-1460505748561-0', 'video') ],
- adUnitCodes: ['div-gpt-ad-1460505748561-0']
- });
-
- response = videoResponse;
- response.tags[0].ads[0].cpm = 3.4288;
-
- auction.callBids(cbTimeout);
- let bidTargeting = targeting.getAllTargeting();
- expect(bidTargeting['div-gpt-ad-1460505748561-0']['hb_pb']).to.equal('3.00');
- });
- });
-
describe('getBidResponses', function () {
it('should return expected bid responses when not passed an adunitCode', function () {
var result = $$PREBID_GLOBAL$$.getBidResponses();
From e489aed7422d91e05f3f3e711ceea85ce5ca4df7 Mon Sep 17 00:00:00 2001
From: adg
Date: Tue, 23 Oct 2018 18:31:07 +0200
Subject: [PATCH 49/62] Fix API calls for rivr analytics impressions and clicks
---
modules/rivrAnalyticsAdapter.js | 18 ++++++++++++------
test/spec/modules/rivrAnalyticsAdapter_spec.js | 11 ++++++++---
2 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 6dfe8f6b2c2..c8616894826 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -62,7 +62,6 @@ export function sendAuction() {
`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`,
() => {},
JSON.stringify(req),
- // TODO extract this object to variable
{
contentType: 'application/json',
customHeaders: {
@@ -80,7 +79,7 @@ export function sendImpressions() {
let impressionsReq = Object.assign({}, {impressions});
logInfo('sending impressions request to analytics => ', impressionsReq);
ajax(
- `http://${rivrAnalytics.context.host}/impressions`,
+ `http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/impressions`,
() => {},
JSON.stringify(impressionsReq),
{
@@ -240,10 +239,17 @@ export function reportClickEvent(event) {
'click_url': clickUrl
};
logInfo('Sending click events with parameters: ', req);
-
- // TODO add Authentication header
- ajax(`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/clicks`, () => {
- }, JSON.stringify(req));
+ ajax(
+ `http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/clicks`,
+ () => {},
+ JSON.stringify(req),
+ {
+ contentType: 'application/json',
+ customHeaders: {
+ 'Authorization': 'Basic ' + rivrAnalytics.context.authToken
+ }
+ }
+ );
};
function addClickHandler(bannerId) {
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index dca63bf935e..f903f6e9c2d 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -358,8 +358,10 @@ describe('RIVR Analytics adapter', () => {
it('sendImpressions(), when authToken is defined and there are impressions, it sends impressions to the tracker', () => {
const aMockString = 'anImpressionPropertyValue';
const IMPRESSION_MOCK = { anImpressionProperty: aMockString };
+ const CLIENT_ID_MOCK = 'aClientID';
analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
analyticsAdapter.context.authToken = 'anAuthToken';
+ analyticsAdapter.context.clientID = CLIENT_ID_MOCK;
analyticsAdapter.context.queue = new ExpiringQueue(
() => {},
() => {},
@@ -376,12 +378,13 @@ describe('RIVR Analytics adapter', () => {
expect(ajaxStub.callCount).to.be.equal(1);
expect(payload.impressions.length).to.be.equal(1);
- expect(ajaxStub.getCall(0).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/impressions/);
+ expect(ajaxStub.getCall(0).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/aClientID\/impressions/);
expect(payload.impressions[0].anImpressionProperty).to.be.equal(aMockString);
});
- it('reportClickEvent(), when authToken is not defined, it calls endpoint', () => {
+ it('reportClickEvent() calls endpoint', () => {
const CLIENT_ID_MOCK = 'aClientId';
+ const AUTH_TOKEN_MOCK = 'aToken';
const CLICK_URL_MOCK = 'clickURLMock';
const EVENT_MOCK = {
currentTarget: {
@@ -397,7 +400,7 @@ describe('RIVR Analytics adapter', () => {
}
};
analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
- analyticsAdapter.context.authToken = undefined;
+ analyticsAdapter.context.authToken = AUTH_TOKEN_MOCK;
analyticsAdapter.context.clientID = CLIENT_ID_MOCK;
analyticsAdapter.context.auctionObject.nullProperty = null;
analyticsAdapter.context.auctionObject.notNullProperty = 'aValue';
@@ -407,9 +410,11 @@ describe('RIVR Analytics adapter', () => {
reportClickEvent(EVENT_MOCK);
const payload = JSON.parse(ajaxStub.getCall(0).args[2]);
+ const options = ajaxStub.getCall(0).args[3];
expect(ajaxStub.callCount).to.be.equal(1);
expect(ajaxStub.getCall(0).args[0]).to.match(/http:\/\/tracker.rivr.simplaex.com\/aClientId\/clicks/);
+ expect(options.customHeaders.Authorization).to.equal('Basic aToken');
expect(payload.timestamp).to.be.equal('1970-01-01T00:00:00.000Z');
expect(payload.request_id).to.be.a('string');
expect(payload.click_url).to.be.equal(CLICK_URL_MOCK);
From 37fabf1fdcebb1bd6912e24180f3483025a764f7 Mon Sep 17 00:00:00 2001
From: adg
Date: Wed, 31 Oct 2018 12:45:26 +0100
Subject: [PATCH 50/62] RVR-2005 - Change auction object model
---
modules/rivrAnalyticsAdapter.js | 185 +++++++++++-------
.../spec/modules/rivrAnalyticsAdapter_spec.js | 17 ++
2 files changed, 135 insertions(+), 67 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index c8616894826..40d00608afa 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -3,7 +3,7 @@ import includes from 'core-js/library/fn/array/includes';
import adapter from 'src/AnalyticsAdapter';
import CONSTANTS from 'src/constants.json';
import adaptermanager from 'src/adaptermanager';
-import { logInfo, generateUUID } from 'src/utils';
+import { logInfo, generateUUID, timestamp } from 'src/utils';
const analyticsType = 'endpoint';
const DEFAULT_HOST = 'tracker.rivr.simplaex.com';
@@ -23,7 +23,7 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
rivrAnalytics.context.queue.init();
}
if (rivrAnalytics.context.auctionObject) {
- rivrAnalytics.context.auctionObject = fulfillAuctionObject();
+ rivrAnalytics.context.auctionObject = createNewAuctionObject();
saveUnoptimisedParams();
fetchLocalization();
}
@@ -56,7 +56,7 @@ export function sendAuction() {
removeEmptyProperties(rivrAnalytics.context.auctionObject);
let auctionObject = rivrAnalytics.context.auctionObject;
let req = Object.assign({}, {Auction: auctionObject});
- rivrAnalytics.context.auctionObject = fulfillAuctionObject();
+ rivrAnalytics.context.auctionObject = createNewAuctionObject();
logInfo('sending request to analytics => ', req);
ajax(
`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`,
@@ -158,12 +158,10 @@ export function setAuctionAbjectPosition(position) {
}
function getPlatformType() {
- if (navigator.userAgent.match(/mobile/i)) {
- return 'Mobile';
- } else if (navigator.userAgent.match(/iPad|Android|Touch/i)) {
- return 'Tablet';
+ if (navigator.userAgent.match(/mobile/i) || navigator.userAgent.match(/iPad|Android|Touch/i)) {
+ return 1;
} else {
- return 'Desktop';
+ return 2;
}
};
@@ -314,68 +312,122 @@ function addHandlers(bannersIds) {
})
};
-function fulfillAuctionObject() {
- let newAuction = {
- id: null,
- timestamp: null,
- at: null,
- bcat: [],
- imp: [],
- app: {
- id: null,
- name: null,
- domain: window.location.href,
- bundle: null,
- cat: [],
- publisher: {
- id: null,
- name: null
- }
+export function createNewAuctionObject() {
+ const auction = {
+ id: '',
+ publisher: rivrAnalytics.context.clientID,
+ blockedCategories: [''],
+ timestamp: timestamp(),
+ user: {
+ id: ''
},
site: {
- id: null,
- name: null,
- domain: window.location.href,
- cat: [],
- publisher: {
- id: null,
- name: null
- }
+ domain: window.location.host,
+ page: window.location.pathname,
+ categories: ['']
},
- device: {
- geo: {
- city: null,
- country: null,
- region: null,
- zip: null,
- type: null,
- metro: null
- },
- devicetype: getPlatformType(),
- osv: null,
- os: null,
- model: null,
- make: null,
- carrier: null,
- ip: null,
- didsha1: null,
- dpidmd5: null,
- ext: {
- uid: null
+ impressions: [
+ {
+ id: '',
+ adSpotId: '',
+ adType: '',
+ bidFloor: 0.0,
+ acceptedSizes: [
+ {
+ h: 0,
+ w: 0
+ }
+ ],
+ banner: {
+ h: 0,
+ w: 0,
+ pos: ''
+ },
}
- },
- user: {
- id: null,
- yob: null,
- gender: null,
- },
- bidResponses: [],
- bidRequests: [],
- 'ext.rivr.optimiser': localStorage.getItem('rivr_should_optimise') || 'unoptimised',
- modelVersion: localStorage.getItem('rivr_model_version') || null,
- 'ext.rivr.originalvalues': []
- };
- return newAuction;
+ ],
+ bidders: [
+ {
+ id: '',
+ bids: [
+ {
+ adomain: [''],
+ clearPrice: 0.0,
+ impId: '',
+ price: 0.0,
+ status: 0
+ }
+ ]
+ }
+ ],
+ device: {
+ userAgent: navigator.userAgent,
+ browser: '',
+ deviceType: getPlatformType()
+ }
+ }
+
+ return auction;
+
+ // let newAuction = {
+ // id: null,
+ // timestamp: null,
+ // at: null,
+ // bcat: [],
+ // imp: [],
+ // app: {
+ // id: null,
+ // name: null,
+ // domain: window.location.href,
+ // bundle: null,
+ // cat: [],
+ // publisher: {
+ // id: null,
+ // name: null
+ // }
+ // },
+ // site: {
+ // id: null,
+ // name: null,
+ // domain: window.location.href,
+ // cat: [],
+ // publisher: {
+ // id: null,
+ // name: null
+ // }
+ // },
+ // device: {
+ // geo: {
+ // city: null,
+ // country: null,
+ // region: null,
+ // zip: null,
+ // type: null,
+ // metro: null
+ // },
+ // devicetype: getPlatformType(),
+ // osv: null,
+ // os: null,
+ // model: null,
+ // make: null,
+ // carrier: null,
+ // ip: null,
+ // didsha1: null,
+ // dpidmd5: null,
+ // ext: {
+ // uid: null
+ // }
+ // },
+ // user: {
+ // id: null,
+ // yob: null,
+ // gender: null,
+ // },
+ // bidResponses: [],
+ // bidRequests: [],
+ // 'ext.rivr.optimiser': localStorage.getItem('rivr_should_optimise') || 'unoptimised',
+ // modelVersion: localStorage.getItem('rivr_model_version') || null,
+ // 'ext.rivr.originalvalues': []
+ // };
};
function saveUnoptimisedParams() {
@@ -528,7 +580,6 @@ rivrAnalytics.enableAnalytics = (config) => {
}
rivrAnalytics.context = {
host: config.options.host || DEFAULT_HOST,
- pubId: config.options.pubId,
auctionObject: {},
adUnits: copiedUnits,
clientID: config.options.clientID,
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index f903f6e9c2d..965c38a11ab 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -9,6 +9,7 @@ import {
dataLoaderForHandler,
pinHandlerToHTMLElement,
setAuctionAbjectPosition,
+ createNewAuctionObject,
} from 'modules/rivrAnalyticsAdapter';
import {expect} from 'chai';
import adaptermanager from 'src/adaptermanager';
@@ -21,6 +22,7 @@ describe('RIVR Analytics adapter', () => {
const EXPIRING_QUEUE_TIMEOUT = 4000;
const EXPIRING_QUEUE_TIMEOUT_MOCK = 100;
const PUBLISHER_ID_MOCK = 777;
+ const RVR_CLIENT_ID_MOCK = 'aCliendId';
const EMITTED_AUCTION_ID = 1;
const TRACKER_BASE_URL_MOCK = 'tracker.rivr.simplaex.com';
let sandbox;
@@ -43,6 +45,7 @@ describe('RIVR Analytics adapter', () => {
adaptermanager.enableAnalytics({
provider: 'rivr',
options: {
+ clientID: RVR_CLIENT_ID_MOCK,
pubId: PUBLISHER_ID_MOCK,
adUnits: [utils.deepClone(AD_UNITS_MOCK)]
}
@@ -547,6 +550,20 @@ describe('RIVR Analytics adapter', () => {
expect(analyticsAdapter.context.auctionObject.device.geo.lat).to.be.equal('aLatitude');
});
+ it.only('createNewAuctionObject(), it creates a new auction object', () => {
+ const MILLIS_FROM_EPOCH_TO_NOW_MOCK = 123456;
+ timer.tick(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
+
+ const result = createNewAuctionObject();
+
+ expect(result.device.deviceType).to.be.equal(2);
+ expect(result.publisher).to.be.equal(RVR_CLIENT_ID_MOCK);
+ expect(result.device.userAgent).to.be.equal(navigator.userAgent);
+ expect(result.timestamp).to.be.equal(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
+ expect(result.site.domain.substring(0, 9)).to.be.equal('localhost');
+ expect(result.site.page).to.be.equal('/context.html');
+ });
+
const AD_UNITS_MOCK = [
{
code: 'banner-container1',
From d4c53788ac1684324237ec718089a1a097215e0c Mon Sep 17 00:00:00 2001
From: adg
Date: Thu, 1 Nov 2018 12:22:52 +0100
Subject: [PATCH 51/62] RVR-2005 - Set rvr_usr_id cookie
---
modules/rivrAnalyticsAdapter.js | 26 +++++++---
.../spec/modules/rivrAnalyticsAdapter_spec.js | 52 ++++++++++++++++++-
2 files changed, 70 insertions(+), 8 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 40d00608afa..9c2c32f643d 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -6,6 +6,7 @@ import adaptermanager from 'src/adaptermanager';
import { logInfo, generateUUID, timestamp } from 'src/utils';
const analyticsType = 'endpoint';
+const rivrUsrIdCookieKey = 'rvr_usr_id';
const DEFAULT_HOST = 'tracker.rivr.simplaex.com';
const DEFAULT_QUEUE_TIMEOUT = 4000;
@@ -24,7 +25,7 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
}
if (rivrAnalytics.context.auctionObject) {
rivrAnalytics.context.auctionObject = createNewAuctionObject();
- saveUnoptimisedParams();
+ saveUnoptimisedAdUnits();
fetchLocalization();
}
handler = trackAuctionInit;
@@ -319,12 +320,12 @@ export function createNewAuctionObject() {
blockedCategories: [''],
timestamp: timestamp(),
user: {
- id: ''
+ id: rivrAnalytics.context.userId
},
site: {
domain: window.location.host,
page: window.location.pathname,
- categories: ['']
+ categories: rivrAnalytics.context.siteCategories
},
impressions: [
{
@@ -363,7 +364,8 @@ export function createNewAuctionObject() {
userAgent: navigator.userAgent,
browser: '',
deviceType: getPlatformType()
- }
+ },
+ 'ext.rivr.originalvalues': []
}
return auction;
@@ -430,7 +432,7 @@ export function createNewAuctionObject() {
// };
};
-function saveUnoptimisedParams() {
+export function saveUnoptimisedAdUnits() {
let units = rivrAnalytics.context.adUnits;
if (units) {
if (units.length > 0) {
@@ -448,7 +450,7 @@ function saveUnoptimisedParams() {
}
};
-function connectAllUnits(units) {
+export function connectAllUnits(units) {
return units.reduce((acc, units) => {
units.forEach((unit) => acc.push(unit))
return acc
@@ -568,6 +570,16 @@ function removeEmptyProperties(obj) {
});
};
+function getCookie(name) {
+ var value = '; ' + document.cookie;
+ var parts = value.split('; ' + name + '=');
+ if (parts.length == 2) return parts.pop().split(';').shift();
+}
+
+function storeAndReturnRivrUsrIdCookie() {
+ return document.cookie = 'rvr_usr_id=' + generateUUID();
+}
+
// save the base class function
rivrAnalytics.originEnableAnalytics = rivrAnalytics.enableAnalytics;
@@ -579,9 +591,11 @@ rivrAnalytics.enableAnalytics = (config) => {
copiedUnits = JSON.parse(stringifiedAdUnits);
}
rivrAnalytics.context = {
+ userId: getCookie(rivrUsrIdCookieKey) || storeAndReturnRivrUsrIdCookie(),
host: config.options.host || DEFAULT_HOST,
auctionObject: {},
adUnits: copiedUnits,
+ siteCategories: config.options.siteCategories || [],
clientID: config.options.clientID,
authToken: config.options.authToken,
queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 965c38a11ab..3951c5ab3ae 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -10,6 +10,7 @@ import {
pinHandlerToHTMLElement,
setAuctionAbjectPosition,
createNewAuctionObject,
+ connectAllUnits,
} from 'modules/rivrAnalyticsAdapter';
import {expect} from 'chai';
import adaptermanager from 'src/adaptermanager';
@@ -23,8 +24,10 @@ describe('RIVR Analytics adapter', () => {
const EXPIRING_QUEUE_TIMEOUT_MOCK = 100;
const PUBLISHER_ID_MOCK = 777;
const RVR_CLIENT_ID_MOCK = 'aCliendId';
+ const SITE_CATEGORIES_MOCK = ['cat1', 'cat2'];
const EMITTED_AUCTION_ID = 1;
const TRACKER_BASE_URL_MOCK = 'tracker.rivr.simplaex.com';
+ const UUID_REG_EXP = new RegExp('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', 'i');
let sandbox;
let ajaxStub;
let timer;
@@ -47,7 +50,8 @@ describe('RIVR Analytics adapter', () => {
options: {
clientID: RVR_CLIENT_ID_MOCK,
pubId: PUBLISHER_ID_MOCK,
- adUnits: [utils.deepClone(AD_UNITS_MOCK)]
+ adUnits: [utils.deepClone(BANNER_AD_UNITS_MOCK)],
+ siteCategories: SITE_CATEGORIES_MOCK,
}
});
});
@@ -99,6 +103,10 @@ describe('RIVR Analytics adapter', () => {
expect(analyticsAdapter.context).to.have.property('pubId', PUBLISHER_ID_MOCK);
});
+ it.only('enableAnalytics - should set a cookie containing a user id', () => {
+ expect(UUID_REG_EXP.test(analyticsAdapter.context.userId)).to.equal(true);
+ });
+
it('Firing AUCTION_INIT should set auction id of context when AUCTION_INIT event is fired', () => {
events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000});
const auctionId = analyticsAdapter.context.auctionObject.id;
@@ -562,9 +570,20 @@ describe('RIVR Analytics adapter', () => {
expect(result.timestamp).to.be.equal(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
expect(result.site.domain.substring(0, 9)).to.be.equal('localhost');
expect(result.site.page).to.be.equal('/context.html');
+ expect(result.site.categories).to.be.equal(SITE_CATEGORIES_MOCK);
+ });
+
+ it('connectAllUnits(), returns a flattened array with all banner and video adunits', () => {
+ const allAdUnits = [BANNER_AD_UNITS_MOCK, VIDEO_AD_UNITS_MOCK];
+
+ const result = connectAllUnits(allAdUnits);
+
+ expect(result.length).to.be.eql(2);
+ expect(result[0].code).to.be.eql('banner-container1');
+ expect(result[1].code).to.be.eql('video');
});
- const AD_UNITS_MOCK = [
+ const BANNER_AD_UNITS_MOCK = [
{
code: 'banner-container1',
mediaTypes: {
@@ -590,6 +609,35 @@ describe('RIVR Analytics adapter', () => {
}
];
+ const VIDEO_AD_UNITS_MOCK = [
+ {
+ code: 'video',
+ mediaTypes: {
+ video: {
+ context: 'outstream',
+ sizes: [[640, 360], [640, 480]]
+ }
+ },
+ bids: [
+ {
+ bidder: "vuble",
+ params: {
+ env: 'net',
+ pubId: '18',
+ zoneId: '12345',
+ referrer: "http://www.vuble.tv/", // optional
+ floorPrice: 5.00 // optional
+ }
+ },
+ {
+ bidder: 'vertamedia',
+ params: {
+ aid: 331133
+ }
+ }
+ ]
+ }];
+
const REQUEST = {
bidderCode: 'adapter',
auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
From 47126c40812b29111a9a142bd70901ce68832fdc Mon Sep 17 00:00:00 2001
From: adg
Date: Thu, 1 Nov 2018 14:02:39 +0100
Subject: [PATCH 52/62] RVR-2005 - Remove BID_REQUESTED and BID_RESPONSE
handlers
We have the same infos all collected in AUCTION_END
---
modules/rivrAnalyticsAdapter.js | 40 ++++++++++++---------------------
1 file changed, 14 insertions(+), 26 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 9c2c32f643d..cb4c9b088ea 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -30,12 +30,14 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
}
handler = trackAuctionInit;
break;
- case CONSTANTS.EVENTS.BID_REQUESTED:
- handler = trackBidRequest;
- break;
- case CONSTANTS.EVENTS.BID_RESPONSE:
- handler = trackBidResponse;
- break;
+ // TODO remove this. args object will be also found in AUCTION_END event -> args.bidderRequests[i]
+ // case CONSTANTS.EVENTS.BID_REQUESTED:
+ // handler = trackBidRequest;
+ // break;
+ // TODO remove this. args object will be also found in AUCTION_END event -> args.bidsReceived[i]
+ // case CONSTANTS.EVENTS.BID_RESPONSE:
+ // handler = trackBidResponse;
+ // break;
case CONSTANTS.EVENTS.BID_WON:
handler = trackBidWon;
break;
@@ -100,14 +102,15 @@ function trackAuctionInit(args) {
};
function trackBidRequest(args) {
- setCurrentPublisherId(args);
- let bidRequest = args;
- rivrAnalytics.context.auctionObject.bidRequests.push(bidRequest);
+ // TODO remove this. args object will be also found in AUCTION_END event -> args.bidderRequests[i]
+ // let bidRequest = args;
+ // rivrAnalytics.context.auctionObject.bidRequests.push(bidRequest);
};
function trackBidResponse(args) {
- let bidResponse = createBidResponse(args);
- rivrAnalytics.context.auctionObject.bidResponses.push(bidResponse);
+ // TODO remove this. args object will be also found in AUCTION_END event -> args.bidsReceived[i]
+ // let bidResponse = createBidResponse(args);
+ // rivrAnalytics.context.auctionObject.bidResponses.push(bidResponse);
};
function trackBidWon(args) {
@@ -126,21 +129,6 @@ function trackBidTimeout(args) {
return [args];
};
-function setCurrentPublisherId(bidRequested) {
- let site = rivrAnalytics.context.auctionObject.site;
- let app = rivrAnalytics.context.auctionObject.app;
- let pubId = rivrAnalytics.context.pubId;
- if (!site.publisher.id || app.publisher.id) {
- if (pubId) {
- site.publisher.id = pubId;
- app.publisher.id = pubId;
- } else {
- site.publisher.id = bidRequested.bids[0].crumbs.pubcid;
- app.publisher.id = bidRequested.bids[0].crumbs.pubcid;
- }
- }
-};
-
export function fetchLocalization() {
if (navigator.permissions) {
navigator.permissions.query({ name: 'geolocation' }).then((permission) => {
From 7f9be8fde4c54bc61f6aa81cf58d80d4cceb25fb Mon Sep 17 00:00:00 2001
From: adg
Date: Thu, 1 Nov 2018 17:49:57 +0100
Subject: [PATCH 53/62] RVR-2005 - build Bidders Array From Auction End
---
modules/rivrAnalyticsAdapter.js | 138 ++++++--------
.../spec/modules/rivrAnalyticsAdapter_spec.js | 179 +++++++++++++++++-
2 files changed, 237 insertions(+), 80 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index cb4c9b088ea..643a8b6a664 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -1,5 +1,4 @@
import {ajax} from 'src/ajax';
-import includes from 'core-js/library/fn/array/includes';
import adapter from 'src/AnalyticsAdapter';
import CONSTANTS from 'src/constants.json';
import adaptermanager from 'src/adaptermanager';
@@ -101,17 +100,17 @@ function trackAuctionInit(args) {
rivrAnalytics.context.auctionObject.id = args.auctionId;
};
-function trackBidRequest(args) {
- // TODO remove this. args object will be also found in AUCTION_END event -> args.bidderRequests[i]
- // let bidRequest = args;
- // rivrAnalytics.context.auctionObject.bidRequests.push(bidRequest);
-};
+// TODO remove this. args object will be also found in AUCTION_END event -> args.bidderRequests[i]
+// function trackBidRequest(args) {
+// let bidRequest = args;
+// rivrAnalytics.context.auctionObject.bidRequests.push(bidRequest);
+// };
-function trackBidResponse(args) {
- // TODO remove this. args object will be also found in AUCTION_END event -> args.bidsReceived[i]
- // let bidResponse = createBidResponse(args);
- // rivrAnalytics.context.auctionObject.bidResponses.push(bidResponse);
-};
+// TODO remove this. args object will be also found in AUCTION_END event -> args.bidsReceived[i]
+// function trackBidResponse(args) {
+// let bidResponse = createBidResponse(args);
+// rivrAnalytics.context.auctionObject.bidResponses.push(bidResponse);
+// };
function trackBidWon(args) {
let auctionObject = rivrAnalytics.context.auctionObject;
@@ -120,11 +119,33 @@ function trackBidWon(args) {
assignBidWonStatusToResponse(args);
};
-function trackAuctionEnd(args) {
+export function trackAuctionEnd(args) {
rivrAnalytics.context.auctionTimeEnd = Date.now();
- fillBidResponsesOfUnrespondedBidRequests();
+ rivrAnalytics.context.auctionObject.bidders = buildBiddersArrayFromAuctionEnd(args);
};
+function buildBiddersArrayFromAuctionEnd(args) {
+ return args.bidderRequests.map((bidderRequest) => {
+ const bidder = {};
+ bidder.id = bidderRequest.bidderCode;
+ bidder.bids = bidderRequest.bids.map((bid) => {
+ const bidReceivedForThisRequest = args.bidsReceived.find((bidReceived) => {
+ return bidderRequest.bidderCode === bidReceived.bidderCode &&
+ bid.bidId === bidReceived.adId &&
+ bid.adUnitCode === bidReceived.adUnitCode;
+ });
+ return {
+ adomain: [''],
+ clearPrice: 0.0,
+ impId: bid.adUnitCode,
+ price: bidReceivedForThisRequest ? bidReceivedForThisRequest.cpm : 0.0,
+ status: 0
+ };
+ });
+ return bidder;
+ });
+}
+
function trackBidTimeout(args) {
return [args];
};
@@ -154,46 +175,34 @@ function getPlatformType() {
}
};
-function createBidResponse(bidResponseEvent) {
- return {
- timestamp: bidResponseEvent.responseTimestamp,
- status: bidResponseEvent.getStatusCode(),
- total_duration: bidResponseEvent.timeToRespond,
- bidderId: null,
- bidder_name: bidResponseEvent.bidder,
- cur: bidResponseEvent.currency,
- seatbid: [
- {
- seat: null,
- bid: [
- {
- status: 2,
- clear_price: bidResponseEvent.cpm,
- attr: [],
- crid: bidResponseEvent.creativeId,
- cid: null,
- id: null,
- adid: bidResponseEvent.adId,
- adomain: [],
- iurl: null
- }
- ]
- }
- ]
- }
-};
-
-function createSingleEmptyBidResponse(bidResponse) {
- return {
- timestamp: bidResponse.start,
- total_duration: null,
- bidderId: null,
- bidder_name: bidResponse.bidder,
- cur: null,
- response: 'noBid',
- seatbid: []
- }
-};
+// function createBidResponse(bidResponseEvent) {
+// return {
+// timestamp: bidResponseEvent.responseTimestamp,
+// status: bidResponseEvent.getStatusCode(),
+// total_duration: bidResponseEvent.timeToRespond,
+// bidderId: null,
+// bidder_name: bidResponseEvent.bidder,
+// cur: bidResponseEvent.currency,
+// seatbid: [
+// {
+// seat: null,
+// bid: [
+// {
+// status: 2,
+// clear_price: bidResponseEvent.cpm,
+// attr: [],
+// crid: bidResponseEvent.creativeId,
+// cid: null,
+// id: null,
+// adid: bidResponseEvent.adId,
+// adomain: [],
+// iurl: null
+// }
+// ]
+// }
+// ]
+// }
+// };
function createAuctionImpression(bidWonEvent) {
return {
@@ -528,29 +537,6 @@ function assignBidWonStatusToResponse(wonBid) {
});
};
-function fillBidResponsesOfUnrespondedBidRequests() {
- let unRespondedBidRequests = getAllUnrespondedBidRequests();
- unRespondedBidRequests.forEach((bid) => {
- let emptyBidResponse = createSingleEmptyBidResponse(bid);
- rivrAnalytics.context.auctionObject.bidResponses.push(emptyBidResponse);
- });
-};
-
-function getAllUnrespondedBidRequests() {
- let respondedBidIds = getAllRespondedBidIds();
- let bidRequests = rivrAnalytics.context.auctionObject.bidRequests;
- let allNotRespondedBidRequests = bidRequests.reduce((cache, requestBidder) => {
- let notRespondedBids = requestBidder.bids.filter((bid) => !includes(respondedBidIds, bid.bidId));
- notRespondedBids.forEach((bid) => bid.start = requestBidder.start);
- return cache.concat(notRespondedBids);
- }, []);
- return allNotRespondedBidRequests;
-};
-
-function getAllRespondedBidIds() {
- return rivrAnalytics.context.auctionObject.bidResponses.map((response) => response.seatbid[0].bid[0].adid);
-};
-
function removeEmptyProperties(obj) {
Object.keys(obj).forEach(function(key) {
if (obj[key] && typeof obj[key] === 'object') removeEmptyProperties(obj[key])
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 3951c5ab3ae..96b16bf29f5 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -11,6 +11,7 @@ import {
setAuctionAbjectPosition,
createNewAuctionObject,
connectAllUnits,
+ trackAuctionEnd,
} from 'modules/rivrAnalyticsAdapter';
import {expect} from 'chai';
import adaptermanager from 'src/adaptermanager';
@@ -103,7 +104,7 @@ describe('RIVR Analytics adapter', () => {
expect(analyticsAdapter.context).to.have.property('pubId', PUBLISHER_ID_MOCK);
});
- it.only('enableAnalytics - should set a cookie containing a user id', () => {
+ it('enableAnalytics - should set a cookie containing a user id', () => {
expect(UUID_REG_EXP.test(analyticsAdapter.context.userId)).to.equal(true);
});
@@ -558,7 +559,7 @@ describe('RIVR Analytics adapter', () => {
expect(analyticsAdapter.context.auctionObject.device.geo.lat).to.be.equal('aLatitude');
});
- it.only('createNewAuctionObject(), it creates a new auction object', () => {
+ it('createNewAuctionObject(), it creates a new auction object', () => {
const MILLIS_FROM_EPOCH_TO_NOW_MOCK = 123456;
timer.tick(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
@@ -583,6 +584,26 @@ describe('RIVR Analytics adapter', () => {
expect(result[1].code).to.be.eql('video');
});
+ it.only('trackAuctionEnd(), populates the bidders array from bidderRequests and bidsReceived', () => {
+ trackAuctionEnd(AUCTION_END_EVENT_FOR_BIDDER_ARRAY_MOCK);
+
+ const result = analyticsAdapter.context.auctionObject.bidders;
+
+ expect(result.length).to.be.eql(3);
+
+ expect(result[0].id).to.be.eql('vuble');
+ expect(result[0].bids[0].price).to.be.eql(0);
+
+ expect(result[1].id).to.be.eql('vertamedia');
+ expect(result[1].bids[0].price).to.be.eql(0);
+
+ expect(result[2].id).to.be.eql('appnexus');
+ expect(result[2].bids[0].price).to.be.eql(0.5);
+ expect(result[2].bids[0].impId).to.be.eql('/19968336/header-bid-tag-0');
+ expect(result[2].bids[1].price).to.be.eql(0.7);
+ expect(result[2].bids[1].impId).to.be.eql('/19968336/header-bid-tag-1');
+ });
+
const BANNER_AD_UNITS_MOCK = [
{
code: 'banner-container1',
@@ -620,12 +641,12 @@ describe('RIVR Analytics adapter', () => {
},
bids: [
{
- bidder: "vuble",
+ bidder: 'vuble',
params: {
env: 'net',
pubId: '18',
zoneId: '12345',
- referrer: "http://www.vuble.tv/", // optional
+ referrer: 'http://www.vuble.tv/', // optional
floorPrice: 5.00 // optional
}
},
@@ -764,4 +785,154 @@ describe('RIVR Analytics adapter', () => {
'ext.rivr.originalvalues': []
}
};
+
+ const AUCTION_END_EVENT_FOR_BIDDER_ARRAY_MOCK = {
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ auctionStart: 1540560217395,
+ auctionEnd: 1540560217703,
+ auctionStatus: 'completed',
+ adUnitCodes: [
+ '/19968336/header-bid-tag-0',
+ '/19968336/header-bid-tag-1',
+ 'video'
+ ],
+ bidderRequests: [
+ {
+ bidderCode: 'vuble',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidderRequestId: '1bb11e055665bc',
+ bids: [
+ {
+ bidder: 'vuble',
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ },
+ adUnitCode: 'video',
+ transactionId: 'df11a105-4eef-4ceb-bbc3-a49224f7c49d',
+ bidId: '2859b890da7418',
+ bidderRequestId: '1bb11e055665bc',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ src: 'client',
+ bidRequestsCount: 1
+ }
+ ],
+ auctionStart: 1540560217395,
+ timeout: 3000,
+ refererInfo: {
+ referer: 'http: //localhost: 8080/',
+ reachedTop: true,
+ numIframes: 0,
+ stack: [
+ 'http://localhost:8080/'
+ ]
+ },
+ start: 1540560217401,
+ doneCbCallCount: 0
+ },
+ {
+ bidderCode: 'vertamedia',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidderRequestId: '3c2cbf7f1466cb',
+ bids: [
+ {
+ bidder: 'vertamedia',
+ params: {
+ aid: 331133
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ },
+ adUnitCode: 'video',
+ transactionId: 'df11a105-4eef-4ceb-bbc3-a49224f7c49d',
+ bidId: '45b3ad5c2dc794',
+ bidderRequestId: '3c2cbf7f1466cb',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidRequestsCount: 1
+ }
+ ],
+ auctionStart: 1540560217395,
+ timeout: 3000,
+ start: 1540560217401
+ },
+ {
+ bidderCode: 'appnexus',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidderRequestId: '5312eef4418cd7',
+ bids: [
+ {
+ bidder: 'appnexus',
+ params: {
+ placementId: 13144370
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ },
+ adUnitCode: '/19968336/header-bid-tag-0',
+ transactionId: 'aee9bf8d-6d8f-425b-a42a-52c875371ebc',
+ bidId: '6de82e80757293',
+ bidderRequestId: '5312eef4418cd7',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ src: 'client',
+ bidRequestsCount: 1
+ },
+ {
+ bidder: 'appnexus',
+ params: {
+ placementId: 13144370
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ },
+ adUnitCode: '/19968336/header-bid-tag-1',
+ transactionId: '3d5f0f89-e9cd-4714-b314-3f0fb7fcf8e3',
+ bidId: '7e1a45d85bd57c',
+ bidderRequestId: '5312eef4418cd7',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ src: 'client',
+ bidRequestsCount: 1
+ }
+ ],
+ auctionStart: 1540560217395,
+ timeout: 3000,
+ start: 1540560217403,
+ doneCbCallCount: 0
+ }
+ ],
+ bidsReceived: [
+ {
+ bidderCode: 'appnexus',
+ adId: '6de82e80757293',
+ mediaType: 'banner',
+ source: 'client',
+ requestId: '6de82e80757293',
+ cpm: 0.5,
+ creativeId: 96846035,
+ appnexus: {
+ buyerMemberId: 9325
+ },
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidder: 'appnexus',
+ adUnitCode: '/19968336/header-bid-tag-0',
+ },
+ {
+ bidderCode: 'appnexus',
+ adId: '7e1a45d85bd57c',
+ mediaType: 'banner',
+ source: 'client',
+ requestId: '7e1a45d85bd57c',
+ cpm: 0.7,
+ creativeId: 96846035,
+ appnexus: {
+ buyerMemberId: 9325
+ },
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidder: 'appnexus',
+ adUnitCode: '/19968336/header-bid-tag-1',
+ }
+ ],
+ winningBids: [
+
+ ],
+ timeout: 3000
+ };
});
From 11bd67361104d4c6dbfa2222e99442f306da1a4a Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 2 Nov 2018 11:19:43 +0100
Subject: [PATCH 54/62] RVR-2005 - build impressions Array From Auction End
---
modules/rivrAnalyticsAdapter.js | 44 +++-
.../spec/modules/rivrAnalyticsAdapter_spec.js | 209 +++++++++++++++++-
2 files changed, 247 insertions(+), 6 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 643a8b6a664..7f3873ad9b7 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -122,14 +122,52 @@ function trackBidWon(args) {
export function trackAuctionEnd(args) {
rivrAnalytics.context.auctionTimeEnd = Date.now();
rivrAnalytics.context.auctionObject.bidders = buildBiddersArrayFromAuctionEnd(args);
+ rivrAnalytics.context.auctionObject.impressions = buildImpressionsArrayFromAuctionEnd(args);
};
-function buildBiddersArrayFromAuctionEnd(args) {
- return args.bidderRequests.map((bidderRequest) => {
+function buildImpressionsArrayFromAuctionEnd(auctionEndEvent) {
+ return auctionEndEvent.adUnits.map((adUnit) => {
+ const impression = {};
+ impression.id = adUnit.code;
+ impression.adType = 'unknown';
+ impression.acceptedSizes = [];
+ const bidReceivedForThisAdUnit = auctionEndEvent.bidsReceived.find((bidReceived) => {
+ return adUnit.code === bidReceived.adUnitCode;
+ });
+ if (adUnit.mediaTypes) {
+ let acceptedSizes = [];
+ if (adUnit.mediaTypes.banner) {
+ buildAdTypeDependentFieldsForImpression(impression, 'banner', adUnit, bidReceivedForThisAdUnit);
+ } else if (adUnit.mediaTypes.video) {
+ buildAdTypeDependentFieldsForImpression(impression, 'video', adUnit, bidReceivedForThisAdUnit);
+ }
+ }
+ return impression;
+ });
+}
+
+function buildAdTypeDependentFieldsForImpression(impression, adType, adUnit, bidReceivedForThisAdUnit) {
+ impression.adType = adType;
+ impression.acceptedSizes = adUnit.mediaTypes[adType].sizes.map((acceptedSize) => {
+ return {
+ w: acceptedSize[0],
+ h: acceptedSize[1]
+ };
+ });
+ if (bidReceivedForThisAdUnit) {
+ impression[adType] = {
+ w: bidReceivedForThisAdUnit.width,
+ h: bidReceivedForThisAdUnit.height
+ };
+ }
+}
+
+function buildBiddersArrayFromAuctionEnd(auctionEndEvent) {
+ return auctionEndEvent.bidderRequests.map((bidderRequest) => {
const bidder = {};
bidder.id = bidderRequest.bidderCode;
bidder.bids = bidderRequest.bids.map((bid) => {
- const bidReceivedForThisRequest = args.bidsReceived.find((bidReceived) => {
+ const bidReceivedForThisRequest = auctionEndEvent.bidsReceived.find((bidReceived) => {
return bidderRequest.bidderCode === bidReceived.bidderCode &&
bid.bidId === bidReceived.adId &&
bid.adUnitCode === bidReceived.adUnitCode;
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 96b16bf29f5..ab710f44ebb 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -584,8 +584,8 @@ describe('RIVR Analytics adapter', () => {
expect(result[1].code).to.be.eql('video');
});
- it.only('trackAuctionEnd(), populates the bidders array from bidderRequests and bidsReceived', () => {
- trackAuctionEnd(AUCTION_END_EVENT_FOR_BIDDER_ARRAY_MOCK);
+ it('trackAuctionEnd(), populates the bidders array from bidderRequests and bidsReceived', () => {
+ trackAuctionEnd(AUCTION_END_EVENT_WITH_BID_REQUESTS_AND_BID_RESPONSES_MOCK);
const result = analyticsAdapter.context.auctionObject.bidders;
@@ -604,6 +604,26 @@ describe('RIVR Analytics adapter', () => {
expect(result[2].bids[1].impId).to.be.eql('/19968336/header-bid-tag-1');
});
+ it.only('trackAuctionEnd(), populates the impressions array from adUnits', () => {
+ trackAuctionEnd(AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK);
+
+ const result = analyticsAdapter.context.auctionObject.impressions;
+
+ expect(result.length).to.be.eql(3);
+
+ expect(result[0].id).to.be.eql('/19968336/header-bid-tag-0');
+ expect(result[0].adType).to.be.eql('banner');
+
+ expect(result[1].id).to.be.eql('/19968336/header-bid-tag-1');
+ expect(result[1].adType).to.be.eql('banner');
+ expect(result[1].acceptedSizes).to.be.eql([{w: 728, h: 90}, {w: 970, h: 250}]);
+ expect(result[1].banner).to.be.eql({w: 300, h: 250});
+
+ // expect(result[2].id).to.be.eql('video');
+ // expect(result[2].adType).to.be.eql('video');
+ // expect(result[2].acceptedSizes).to.be.eql([{w: 640, h: 360}, {w: 640, h: 480}]);
+ });
+
const BANNER_AD_UNITS_MOCK = [
{
code: 'banner-container1',
@@ -786,11 +806,194 @@ describe('RIVR Analytics adapter', () => {
}
};
- const AUCTION_END_EVENT_FOR_BIDDER_ARRAY_MOCK = {
+ const AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK = {
+ auctionId:'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ auctionStart:1540560217395,
+ auctionEnd:1540560217703,
+ auctionStatus:'completed',
+ adUnits:[
+ {
+ code:'/19968336/header-bid-tag-0',
+ mediaTypes:{
+ banner:{
+ sizes:[
+ [
+ 300,
+ 250
+ ],
+ [
+ 300,
+ 600
+ ]
+ ]
+ }
+ },
+ bids:[
+ {
+ bidder:'appnexus',
+ params:{
+ placementId:13144370
+ },
+ crumbs:{
+ pubcid:'87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ }
+ }
+ ],
+ transactionId:'aee9bf8d-6d8f-425b-a42a-52c875371ebc',
+ sizes:[
+ [
+ 300,
+ 250
+ ],
+ [
+ 300,
+ 600
+ ]
+ ]
+ },
+ {
+ code:'/19968336/header-bid-tag-1',
+ mediaTypes:{
+ banner:{
+ sizes:[
+ [
+ 728,
+ 90
+ ],
+ [
+ 970,
+ 250
+ ]
+ ]
+ }
+ },
+ bids:[
+ {
+ bidder:'appnexus',
+ params:{
+ placementId:13144370
+ },
+ crumbs:{
+ pubcid:'87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ }
+ }
+ ],
+ transactionId:'3d5f0f89-e9cd-4714-b314-3f0fb7fcf8e3',
+ sizes:[
+ [
+ 728,
+ 90
+ ],
+ [
+ 970,
+ 250
+ ]
+ ]
+ },
+ {
+ code:'video',
+ mediaTypes:{
+ video:{
+ context:'outstream',
+ sizes:[
+ [
+ 640,
+ 360
+ ],
+ [
+ 640,
+ 480
+ ]
+ ]
+ }
+ },
+ bids:[
+ {
+ bidder:'vuble',
+ params:{
+ env:'net',
+ pubId:'18',
+ zoneId:'12345',
+ referrer:'http://www.vuble.tv/',
+ floorPrice:5
+ },
+ crumbs:{
+ pubcid:'87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ }
+ },
+ {
+ bidder:'vertamedia',
+ params:{
+ aid:331133
+ },
+ crumbs:{
+ pubcid:'87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ }
+ }
+ ],
+ transactionId:'df11a105-4eef-4ceb-bbc3-a49224f7c49d'
+ }
+ ],
+ adUnitCodes:[
+ '/19968336/header-bid-tag-0',
+ '/19968336/header-bid-tag-1',
+ 'video'
+ ],
+ bidderRequests: [],
+ bidsReceived:[
+ {
+ bidderCode:'appnexus',
+ width:300,
+ height:250,
+ statusMessage:'Bid available',
+ adId:'6de82e80757293',
+ mediaType:'banner',
+ source:'client',
+ requestId:'6de82e80757293',
+ cpm:0.5,
+ creativeId:96846035,
+ currency:'USD',
+ netRevenue:true,
+ ttl:300,
+ appnexus:{
+ buyerMemberId:9325
+ },
+ ad:'...HTML CONTAINING THE AD...',
+ auctionId:'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ responseTimestamp:1540560217636,
+ requestTimestamp:1540560217403,
+ bidder:'appnexus',
+ adUnitCode:'/19968336/header-bid-tag-1',
+ timeToRespond:233,
+ pbLg:'0.50',
+ pbMg:'0.50',
+ pbHg:'0.50',
+ pbAg:'0.50',
+ pbDg:'0.50',
+ pbCg:'',
+ size:'728x90',
+ adserverTargeting:{
+ hb_bidder:'appnexus',
+ hb_adid:'7e1a45d85bd57c',
+ hb_pb:'0.50',
+ hb_size:'728x90',
+ hb_source:'client',
+ hb_format:'banner'
+ }
+ }
+ ],
+ winningBids:[
+
+ ],
+ timeout:3000
+ };
+
+ const AUCTION_END_EVENT_WITH_BID_REQUESTS_AND_BID_RESPONSES_MOCK = {
auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
auctionStart: 1540560217395,
auctionEnd: 1540560217703,
auctionStatus: 'completed',
+ bidders: [],
adUnitCodes: [
'/19968336/header-bid-tag-0',
'/19968336/header-bid-tag-1',
From f21dd1243941e450405558cef507d8f96c503dcd Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 2 Nov 2018 12:39:19 +0100
Subject: [PATCH 55/62] RVR-2005 - set status of winning bid
---
modules/rivrAnalyticsAdapter.js | 76 ++--
.../spec/modules/rivrAnalyticsAdapter_spec.js | 330 +++++++++++-------
2 files changed, 240 insertions(+), 166 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 7f3873ad9b7..cba0d62fc36 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -113,10 +113,22 @@ function trackAuctionInit(args) {
// };
function trackBidWon(args) {
+ setWinningBidStatus(args);
+};
+
+function setWinningBidStatus(args) {
let auctionObject = rivrAnalytics.context.auctionObject;
- let auctionImpression = createAuctionImpression(args);
- auctionObject.imp.push(auctionImpression);
- assignBidWonStatusToResponse(args);
+ const bidderObjectForThisWonBid = auctionObject.bidders.find((bidder) => {
+ return bidder.id === args.bidderCode;
+ });
+ if (bidderObjectForThisWonBid) {
+ const bidObjectForThisWonBid = bidderObjectForThisWonBid.bids.find((bid) => {
+ return bid.impId === args.adUnitCode;
+ });
+ if (bidObjectForThisWonBid) {
+ bidObjectForThisWonBid.status = 1;
+ }
+ }
};
export function trackAuctionEnd(args) {
@@ -127,23 +139,22 @@ export function trackAuctionEnd(args) {
function buildImpressionsArrayFromAuctionEnd(auctionEndEvent) {
return auctionEndEvent.adUnits.map((adUnit) => {
- const impression = {};
- impression.id = adUnit.code;
- impression.adType = 'unknown';
- impression.acceptedSizes = [];
- const bidReceivedForThisAdUnit = auctionEndEvent.bidsReceived.find((bidReceived) => {
- return adUnit.code === bidReceived.adUnitCode;
- });
+ const impression = {};
+ impression.id = adUnit.code;
+ impression.adType = 'unknown';
+ impression.acceptedSizes = [];
+ const bidReceivedForThisAdUnit = auctionEndEvent.bidsReceived.find((bidReceived) => {
+ return adUnit.code === bidReceived.adUnitCode;
+ });
if (adUnit.mediaTypes) {
- let acceptedSizes = [];
- if (adUnit.mediaTypes.banner) {
- buildAdTypeDependentFieldsForImpression(impression, 'banner', adUnit, bidReceivedForThisAdUnit);
- } else if (adUnit.mediaTypes.video) {
- buildAdTypeDependentFieldsForImpression(impression, 'video', adUnit, bidReceivedForThisAdUnit);
- }
+ if (adUnit.mediaTypes.banner) {
+ buildAdTypeDependentFieldsForImpression(impression, 'banner', adUnit, bidReceivedForThisAdUnit);
+ } else if (adUnit.mediaTypes.video) {
+ buildAdTypeDependentFieldsForImpression(impression, 'video', adUnit, bidReceivedForThisAdUnit);
}
- return impression;
- });
+ }
+ return impression;
+ });
}
function buildAdTypeDependentFieldsForImpression(impression, adType, adUnit, bidReceivedForThisAdUnit) {
@@ -242,23 +253,6 @@ function getPlatformType() {
// }
// };
-function createAuctionImpression(bidWonEvent) {
- return {
- tagid: bidWonEvent.adUnitCode,
- displaymanager: null,
- displaymanagerver: null,
- secure: null,
- bidfloor: null,
- banner: {
- w: bidWonEvent.width,
- h: bidWonEvent.height,
- pos: null,
- expandable: [],
- api: []
- }
- }
-};
-
export function reportClickEvent(event) {
let link = event.currentTarget.getElementsByTagName('a')[0];
let clickUrl;
@@ -563,18 +557,6 @@ export function ExpiringQueue(sendImpressions, sendAuction, ttl, log) {
}
};
-function assignBidWonStatusToResponse(wonBid) {
- let wonBidId = wonBid.adId;
- rivrAnalytics.context.auctionObject.bidResponses.forEach((response) => {
- if (response.seatbid.length > 0) {
- let bidObjectResponse = response.seatbid[0].bid[0];
- if (wonBidId === bidObjectResponse.adid) {
- bidObjectResponse.status = 1
- }
- }
- });
-};
-
function removeEmptyProperties(obj) {
Object.keys(obj).forEach(function(key) {
if (obj[key] && typeof obj[key] === 'object') removeEmptyProperties(obj[key])
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index ab710f44ebb..1fa206815b1 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -248,29 +248,21 @@ describe('RIVR Analytics adapter', () => {
expect(responses[1].total_duration).to.be.eql(null);
});
- it('Firing BID_WON when it happens after BID_RESPONSE should add won event as auction impression to imp array', () => {
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+ it.only('Firing BID_WON should set to 1 the status of the corresponding bid', () => {
+ analyticsAdapter.context.auctionObject = utils.deepClone(AUCTION_OBJECT_AFTER_AUCTION_END_MOCK);
- events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
- events.emit(CONSTANTS.EVENTS.BID_WON, BID_RESPONSE_MOCK);
+ events.emit(CONSTANTS.EVENTS.BID_WON, BID_WON_MOCK);
- const wonEvent = analyticsAdapter.context.auctionObject.imp;
-
- expect(wonEvent.length).to.be.eql(1);
- expect(wonEvent[0]).to.be.eql({
- tagid: 'container-1',
- displaymanager: null,
- displaymanagerver: null,
- secure: null,
- bidfloor: null,
- banner: {
- w: 300,
- h: 250,
- pos: null,
- expandable: [],
- api: []
- }
- });
+ expect(analyticsAdapter.context.auctionObject.bidders.length).to.be.equal(3);
+
+ console.log('analyticsAdapter.context.auctionObject.bidders[0]', analyticsAdapter.context.auctionObject.bidders[0]);
+
+ expect(analyticsAdapter.context.auctionObject.bidders[0].bids[0].status).to.be.equal(0);
+
+ expect(analyticsAdapter.context.auctionObject.bidders[1].bids[0].status).to.be.equal(0);
+
+ expect(analyticsAdapter.context.auctionObject.bidders[2].bids[0].status).to.be.equal(1);
+ expect(analyticsAdapter.context.auctionObject.bidders[2].bids[1].status).to.be.equal(0);
});
it('Firing BID_WON when it happens after BID_RESPONSE should change the status of winning bidResponse to 1', () => {
@@ -604,7 +596,7 @@ describe('RIVR Analytics adapter', () => {
expect(result[2].bids[1].impId).to.be.eql('/19968336/header-bid-tag-1');
});
- it.only('trackAuctionEnd(), populates the impressions array from adUnits', () => {
+ it('trackAuctionEnd(), populates the impressions array from adUnits', () => {
trackAuctionEnd(AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK);
const result = analyticsAdapter.context.auctionObject.impressions;
@@ -619,9 +611,9 @@ describe('RIVR Analytics adapter', () => {
expect(result[1].acceptedSizes).to.be.eql([{w: 728, h: 90}, {w: 970, h: 250}]);
expect(result[1].banner).to.be.eql({w: 300, h: 250});
- // expect(result[2].id).to.be.eql('video');
- // expect(result[2].adType).to.be.eql('video');
- // expect(result[2].acceptedSizes).to.be.eql([{w: 640, h: 360}, {w: 640, h: 480}]);
+ expect(result[2].id).to.be.eql('video');
+ expect(result[2].adType).to.be.eql('video');
+ expect(result[2].acceptedSizes).to.be.eql([{w: 640, h: 360}, {w: 640, h: 480}]);
});
const BANNER_AD_UNITS_MOCK = [
@@ -757,6 +749,53 @@ describe('RIVR Analytics adapter', () => {
size: '300x250'
};
+ const BID_WON_MOCK = {
+ bidderCode: 'appnexus',
+ width: 300,
+ height: 600,
+ statusMessage: 'Bid available',
+ adId: '63301dc59deb3b',
+ mediaType: 'banner',
+ source: 'client',
+ requestId: '63301dc59deb3b',
+ cpm: 0.5,
+ creativeId: 98493581,
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 300,
+ appnexus: {
+ buyerMemberId: 9325
+ },
+ ad: '...HTML CONTAINING THE AD...',
+ auctionId: '1825871c-b4c2-401a-b219-64549d412495',
+ responseTimestamp: 1540560447955,
+ requestTimestamp: 1540560447622,
+ bidder: 'appnexus',
+ adUnitCode: '/19968336/header-bid-tag-0',
+ timeToRespond: 333,
+ pbLg: '0.50',
+ pbMg: '0.50',
+ pbHg: '0.50',
+ pbAg: '0.50',
+ pbDg: '0.50',
+ pbCg: '',
+ size: '300x600',
+ adserverTargeting: {
+ hb_bidder: 'appnexus',
+ hb_adid: '63301dc59deb3b',
+ hb_pb: '0.50',
+ hb_size: '300x600',
+ hb_source: 'client',
+ hb_format: 'banner'
+ },
+ status: 'rendered',
+ params: [
+ {
+ placementId: 13144370
+ }
+ ]
+ };
+
const CONTEXT_AFTER_AUCTION_INIT = {
host: TRACKER_BASE_URL_MOCK,
pubId: PUBLISHER_ID_MOCK,
@@ -807,16 +846,16 @@ describe('RIVR Analytics adapter', () => {
};
const AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK = {
- auctionId:'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
- auctionStart:1540560217395,
- auctionEnd:1540560217703,
- auctionStatus:'completed',
- adUnits:[
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ auctionStart: 1540560217395,
+ auctionEnd: 1540560217703,
+ auctionStatus: 'completed',
+ adUnits: [
{
- code:'/19968336/header-bid-tag-0',
- mediaTypes:{
- banner:{
- sizes:[
+ code: '/19968336/header-bid-tag-0',
+ mediaTypes: {
+ banner: {
+ sizes: [
[
300,
250
@@ -828,19 +867,19 @@ describe('RIVR Analytics adapter', () => {
]
}
},
- bids:[
+ bids: [
{
- bidder:'appnexus',
- params:{
- placementId:13144370
+ bidder: 'appnexus',
+ params: {
+ placementId: 13144370
},
- crumbs:{
- pubcid:'87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
}
}
],
- transactionId:'aee9bf8d-6d8f-425b-a42a-52c875371ebc',
- sizes:[
+ transactionId: 'aee9bf8d-6d8f-425b-a42a-52c875371ebc',
+ sizes: [
[
300,
250
@@ -852,10 +891,10 @@ describe('RIVR Analytics adapter', () => {
]
},
{
- code:'/19968336/header-bid-tag-1',
- mediaTypes:{
- banner:{
- sizes:[
+ code: '/19968336/header-bid-tag-1',
+ mediaTypes: {
+ banner: {
+ sizes: [
[
728,
90
@@ -867,19 +906,19 @@ describe('RIVR Analytics adapter', () => {
]
}
},
- bids:[
+ bids: [
{
- bidder:'appnexus',
- params:{
- placementId:13144370
+ bidder: 'appnexus',
+ params: {
+ placementId: 13144370
},
- crumbs:{
- pubcid:'87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
}
}
],
- transactionId:'3d5f0f89-e9cd-4714-b314-3f0fb7fcf8e3',
- sizes:[
+ transactionId: '3d5f0f89-e9cd-4714-b314-3f0fb7fcf8e3',
+ sizes: [
[
728,
90
@@ -891,11 +930,11 @@ describe('RIVR Analytics adapter', () => {
]
},
{
- code:'video',
- mediaTypes:{
- video:{
- context:'outstream',
- sizes:[
+ code: 'video',
+ mediaTypes: {
+ video: {
+ context: 'outstream',
+ sizes: [
[
640,
360
@@ -907,85 +946,140 @@ describe('RIVR Analytics adapter', () => {
]
}
},
- bids:[
+ bids: [
{
- bidder:'vuble',
- params:{
- env:'net',
- pubId:'18',
- zoneId:'12345',
- referrer:'http://www.vuble.tv/',
- floorPrice:5
+ bidder: 'vuble',
+ params: {
+ env: 'net',
+ pubId: '18',
+ zoneId: '12345',
+ referrer: 'http: //www.vuble.tv/',
+ floorPrice: 5
},
- crumbs:{
- pubcid:'87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
}
},
{
- bidder:'vertamedia',
- params:{
- aid:331133
+ bidder: 'vertamedia',
+ params: {
+ aid: 331133
},
- crumbs:{
- pubcid:'87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
}
}
],
- transactionId:'df11a105-4eef-4ceb-bbc3-a49224f7c49d'
+ transactionId: 'df11a105-4eef-4ceb-bbc3-a49224f7c49d'
}
],
- adUnitCodes:[
+ adUnitCodes: [
'/19968336/header-bid-tag-0',
'/19968336/header-bid-tag-1',
'video'
],
bidderRequests: [],
- bidsReceived:[
+ bidsReceived: [
{
- bidderCode:'appnexus',
- width:300,
- height:250,
- statusMessage:'Bid available',
- adId:'6de82e80757293',
- mediaType:'banner',
- source:'client',
- requestId:'6de82e80757293',
- cpm:0.5,
- creativeId:96846035,
- currency:'USD',
- netRevenue:true,
- ttl:300,
- appnexus:{
- buyerMemberId:9325
+ bidderCode: 'appnexus',
+ width: 300,
+ height: 250,
+ statusMessage: 'Bid available',
+ adId: '6de82e80757293',
+ mediaType: 'banner',
+ source: 'client',
+ requestId: '6de82e80757293',
+ cpm: 0.5,
+ creativeId: 96846035,
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 300,
+ appnexus: {
+ buyerMemberId: 9325
},
- ad:'...HTML CONTAINING THE AD...',
- auctionId:'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
- responseTimestamp:1540560217636,
- requestTimestamp:1540560217403,
- bidder:'appnexus',
- adUnitCode:'/19968336/header-bid-tag-1',
- timeToRespond:233,
- pbLg:'0.50',
- pbMg:'0.50',
- pbHg:'0.50',
- pbAg:'0.50',
- pbDg:'0.50',
- pbCg:'',
- size:'728x90',
- adserverTargeting:{
- hb_bidder:'appnexus',
- hb_adid:'7e1a45d85bd57c',
- hb_pb:'0.50',
- hb_size:'728x90',
- hb_source:'client',
- hb_format:'banner'
+ ad: '...HTML CONTAINING THE AD...',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ responseTimestamp: 1540560217636,
+ requestTimestamp: 1540560217403,
+ bidder: 'appnexus',
+ adUnitCode: '/19968336/header-bid-tag-1',
+ timeToRespond: 233,
+ pbLg: '0.50',
+ pbMg: '0.50',
+ pbHg: '0.50',
+ pbAg: '0.50',
+ pbDg: '0.50',
+ pbCg: '',
+ size: '728x90',
+ adserverTargeting: {
+ hb_bidder: 'appnexus',
+ hb_adid: '7e1a45d85bd57c',
+ hb_pb: '0.50',
+ hb_size: '728x90',
+ hb_source: 'client',
+ hb_format: 'banner'
}
}
],
- winningBids:[
+ winningBids: [],
+ timeout: 3000
+ };
+ const AUCTION_OBJECT_AFTER_AUCTION_END_MOCK = {
+ bidders: [
+ {
+ id: 'vuble',
+ bids: [
+ {
+ adomain: [
+ ''
+ ],
+ clearPrice: 0,
+ impId: 'video',
+ price: 0,
+ status: 0
+ }
+ ]
+ },
+ {
+ id: 'vertamedia',
+ bids: [
+ {
+ adomain: [
+ ''
+ ],
+ clearPrice: 0,
+ impId: 'video',
+ price: 0,
+ status: 0
+ }
+ ]
+ },
+ {
+ id: 'appnexus',
+ bids: [
+ {
+ adomain: [
+ ''
+ ],
+ clearPrice: 0,
+ impId: '/19968336/header-bid-tag-0',
+ price: 0.5,
+ status: 0
+ },
+ {
+ adomain: [
+ ''
+ ],
+ clearPrice: 0,
+ impId: '/19968336/header-bid-tag-1',
+ price: 0.7,
+ status: 0
+ }
+ ]
+ }
],
- timeout:3000
+ impressions: []
};
const AUCTION_END_EVENT_WITH_BID_REQUESTS_AND_BID_RESPONSES_MOCK = {
@@ -993,7 +1087,7 @@ describe('RIVR Analytics adapter', () => {
auctionStart: 1540560217395,
auctionEnd: 1540560217703,
auctionStatus: 'completed',
- bidders: [],
+ adUnits: [],
adUnitCodes: [
'/19968336/header-bid-tag-0',
'/19968336/header-bid-tag-1',
@@ -1133,9 +1227,7 @@ describe('RIVR Analytics adapter', () => {
adUnitCode: '/19968336/header-bid-tag-1',
}
],
- winningBids: [
-
- ],
+ winningBids: [],
timeout: 3000
};
});
From 924d6835cd4d5ffc775ac20e402f3db7b0b4afe2 Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 2 Nov 2018 12:41:04 +0100
Subject: [PATCH 56/62] RVR-2005 - cleanup
---
modules/rivrAnalyticsAdapter.js | 110 --------------------------------
1 file changed, 110 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index cba0d62fc36..c4683c83f57 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -29,14 +29,6 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
}
handler = trackAuctionInit;
break;
- // TODO remove this. args object will be also found in AUCTION_END event -> args.bidderRequests[i]
- // case CONSTANTS.EVENTS.BID_REQUESTED:
- // handler = trackBidRequest;
- // break;
- // TODO remove this. args object will be also found in AUCTION_END event -> args.bidsReceived[i]
- // case CONSTANTS.EVENTS.BID_RESPONSE:
- // handler = trackBidResponse;
- // break;
case CONSTANTS.EVENTS.BID_WON:
handler = trackBidWon;
break;
@@ -100,18 +92,6 @@ function trackAuctionInit(args) {
rivrAnalytics.context.auctionObject.id = args.auctionId;
};
-// TODO remove this. args object will be also found in AUCTION_END event -> args.bidderRequests[i]
-// function trackBidRequest(args) {
-// let bidRequest = args;
-// rivrAnalytics.context.auctionObject.bidRequests.push(bidRequest);
-// };
-
-// TODO remove this. args object will be also found in AUCTION_END event -> args.bidsReceived[i]
-// function trackBidResponse(args) {
-// let bidResponse = createBidResponse(args);
-// rivrAnalytics.context.auctionObject.bidResponses.push(bidResponse);
-// };
-
function trackBidWon(args) {
setWinningBidStatus(args);
};
@@ -224,35 +204,6 @@ function getPlatformType() {
}
};
-// function createBidResponse(bidResponseEvent) {
-// return {
-// timestamp: bidResponseEvent.responseTimestamp,
-// status: bidResponseEvent.getStatusCode(),
-// total_duration: bidResponseEvent.timeToRespond,
-// bidderId: null,
-// bidder_name: bidResponseEvent.bidder,
-// cur: bidResponseEvent.currency,
-// seatbid: [
-// {
-// seat: null,
-// bid: [
-// {
-// status: 2,
-// clear_price: bidResponseEvent.cpm,
-// attr: [],
-// crid: bidResponseEvent.creativeId,
-// cid: null,
-// id: null,
-// adid: bidResponseEvent.adId,
-// adomain: [],
-// iurl: null
-// }
-// ]
-// }
-// ]
-// }
-// };
-
export function reportClickEvent(event) {
let link = event.currentTarget.getElementsByTagName('a')[0];
let clickUrl;
@@ -398,67 +349,6 @@ export function createNewAuctionObject() {
}
return auction;
-
- // let newAuction = {
- // id: null,
- // timestamp: null,
- // at: null,
- // bcat: [],
- // imp: [],
- // app: {
- // id: null,
- // name: null,
- // domain: window.location.href,
- // bundle: null,
- // cat: [],
- // publisher: {
- // id: null,
- // name: null
- // }
- // },
- // site: {
- // id: null,
- // name: null,
- // domain: window.location.href,
- // cat: [],
- // publisher: {
- // id: null,
- // name: null
- // }
- // },
- // device: {
- // geo: {
- // city: null,
- // country: null,
- // region: null,
- // zip: null,
- // type: null,
- // metro: null
- // },
- // devicetype: getPlatformType(),
- // osv: null,
- // os: null,
- // model: null,
- // make: null,
- // carrier: null,
- // ip: null,
- // didsha1: null,
- // dpidmd5: null,
- // ext: {
- // uid: null
- // }
- // },
- // user: {
- // id: null,
- // yob: null,
- // gender: null,
- // },
- // bidResponses: [],
- // bidRequests: [],
- // 'ext.rivr.optimiser': localStorage.getItem('rivr_should_optimise') || 'unoptimised',
- // modelVersion: localStorage.getItem('rivr_model_version') || null,
- // 'ext.rivr.originalvalues': []
- // };
};
export function saveUnoptimisedAdUnits() {
From 6252ac2c2c88a6366c2c779d7f12b70df81e863f Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 2 Nov 2018 12:46:48 +0100
Subject: [PATCH 57/62] RVR-2005 - adapt enableAnalytics() test
---
.../spec/modules/rivrAnalyticsAdapter_spec.js | 83 +------------------
1 file changed, 4 insertions(+), 79 deletions(-)
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 1fa206815b1..ac12a9c5a2b 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -23,7 +23,6 @@ const events = require('../../../src/events');
describe('RIVR Analytics adapter', () => {
const EXPIRING_QUEUE_TIMEOUT = 4000;
const EXPIRING_QUEUE_TIMEOUT_MOCK = 100;
- const PUBLISHER_ID_MOCK = 777;
const RVR_CLIENT_ID_MOCK = 'aCliendId';
const SITE_CATEGORIES_MOCK = ['cat1', 'cat2'];
const EMITTED_AUCTION_ID = 1;
@@ -50,7 +49,6 @@ describe('RIVR Analytics adapter', () => {
provider: 'rivr',
options: {
clientID: RVR_CLIENT_ID_MOCK,
- pubId: PUBLISHER_ID_MOCK,
adUnits: [utils.deepClone(BANNER_AD_UNITS_MOCK)],
siteCategories: SITE_CATEGORIES_MOCK,
}
@@ -97,11 +95,11 @@ describe('RIVR Analytics adapter', () => {
timer.tick(50);
});
- it('enableAnalytics - should configure host and pubId in adapter context', () => {
+ it.only('enableAnalytics - should configure host and clientID in adapter context', () => {
// adaptermanager.enableAnalytics() is called in beforeEach. If only called here it doesn't seem to work.
expect(analyticsAdapter.context).to.have.property('host', TRACKER_BASE_URL_MOCK);
- expect(analyticsAdapter.context).to.have.property('pubId', PUBLISHER_ID_MOCK);
+ expect(analyticsAdapter.context).to.have.property('clientID', RVR_CLIENT_ID_MOCK);
});
it('enableAnalytics - should set a cookie containing a user id', () => {
@@ -150,79 +148,6 @@ describe('RIVR Analytics adapter', () => {
expect(auctionObject3['modelVersion']).to.be.eql(null);
});
- it('Firing BID_REQUESTED it sets app and site publisher id in auction object', () => {
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
-
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
-
- const sitePubcid = analyticsAdapter.context.auctionObject.site.publisher.id;
- const appPubcid = analyticsAdapter.context.auctionObject.app.publisher.id;
- expect(sitePubcid).to.be.eql(PUBLISHER_ID_MOCK);
- expect(appPubcid).to.be.eql(PUBLISHER_ID_MOCK);
- });
-
- it('Firing BID_REQUESTED it adds bid request in bid requests array', () => {
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
-
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
-
- const requestEvent = analyticsAdapter.context.auctionObject.bidRequests;
- expect(requestEvent).to.have.length(1);
- expect(requestEvent[0]).to.be.eql({
- bidderCode: 'adapter',
- auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
- bidderRequestId: '1a6fc81528d0f6',
- bids: [{
- bidder: 'adapter',
- params: {},
- adUnitCode: 'container-1',
- transactionId: 'de90df62-7fd0-4fbc-8787-92d133a7dc06',
- sizes: [[300, 250]],
- bidId: '208750227436c1',
- bidderRequestId: '1a6fc81528d0f6',
- auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f'
- }],
- auctionStart: 1509369418387,
- timeout: 3000,
- start: 1509369418389
- });
- });
-
- it('Firing BID_RESPONSE it inserts bid response object in auctionObject', () => {
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
-
- events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
- const bidResponses = analyticsAdapter.context.auctionObject.bidResponses;
-
- expect(bidResponses).to.have.length(1);
- expect(bidResponses[0]).to.be.eql({
- timestamp: 1509369418832,
- status: 1,
- 'total_duration': 443,
- bidderId: null,
- 'bidder_name': 'adapter',
- cur: 'EU',
- seatbid: [
- {
- seat: null,
- bid: [
- {
- status: 2,
- 'clear_price': 0.015,
- attr: [],
- crid: 999,
- cid: null,
- id: null,
- adid: '208750227436c1',
- adomain: [],
- iurl: null
- }
- ]
- }
- ]
- });
- });
-
it('Firing AUCTION_END it sets auction time end to current time', () => {
analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
@@ -248,7 +173,7 @@ describe('RIVR Analytics adapter', () => {
expect(responses[1].total_duration).to.be.eql(null);
});
- it.only('Firing BID_WON should set to 1 the status of the corresponding bid', () => {
+ it('Firing BID_WON should set to 1 the status of the corresponding bid', () => {
analyticsAdapter.context.auctionObject = utils.deepClone(AUCTION_OBJECT_AFTER_AUCTION_END_MOCK);
events.emit(CONSTANTS.EVENTS.BID_WON, BID_WON_MOCK);
@@ -798,7 +723,7 @@ describe('RIVR Analytics adapter', () => {
const CONTEXT_AFTER_AUCTION_INIT = {
host: TRACKER_BASE_URL_MOCK,
- pubId: PUBLISHER_ID_MOCK,
+ clientID: RVR_CLIENT_ID_MOCK,
queue: {
mockProp: 'mockValue'
},
From c60d1240a6e8627ad081d100462ddc49f6d51d92 Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 2 Nov 2018 13:05:10 +0100
Subject: [PATCH 58/62] RVR-2005 - adapt all tests
---
modules/rivrAnalyticsAdapter.js | 39 ++-------------
.../spec/modules/rivrAnalyticsAdapter_spec.js | 50 +++++--------------
2 files changed, 17 insertions(+), 72 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index c4683c83f57..8fdf817a37d 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -307,45 +307,16 @@ export function createNewAuctionObject() {
page: window.location.pathname,
categories: rivrAnalytics.context.siteCategories
},
- impressions: [
- {
- id: '',
- adSpotId: '',
- adType: '',
- bidFloor: 0.0,
- acceptedSizes: [
- {
- h: 0,
- w: 0
- }
- ],
- banner: {
- h: 0,
- w: 0,
- pos: ''
- },
- }
- ],
- bidders: [
- {
- id: '',
- bids: [
- {
- adomain: [''],
- clearPrice: 0.0,
- impId: '',
- price: 0.0,
- status: 0
- }
- ]
- }
- ],
+ impressions: [],
+ bidders: [],
device: {
userAgent: navigator.userAgent,
browser: '',
deviceType: getPlatformType()
},
- 'ext.rivr.originalvalues': []
+ 'ext.rivr.originalvalues': [],
+ 'ext.rivr.optimiser': localStorage.getItem('rivr_should_optimise') || 'unoptimised',
+ modelVersion: localStorage.getItem('rivr_model_version') || null,
}
return auction;
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index ac12a9c5a2b..63ef6176870 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -95,7 +95,7 @@ describe('RIVR Analytics adapter', () => {
timer.tick(50);
});
- it.only('enableAnalytics - should configure host and clientID in adapter context', () => {
+ it('enableAnalytics - should configure host and clientID in adapter context', () => {
// adaptermanager.enableAnalytics() is called in beforeEach. If only called here it doesn't seem to work.
expect(analyticsAdapter.context).to.have.property('host', TRACKER_BASE_URL_MOCK);
@@ -160,17 +160,13 @@ describe('RIVR Analytics adapter', () => {
expect(endTime).to.be.eql(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
});
- it('Firing AUCTION_END when there are unresponded bid requests should insert then to bidResponses in auctionObject with null duration', () => {
+ it('Firing AUCTION_END populates impressions arrai in auction object', () => {
analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST2);
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST3);
- events.emit(CONSTANTS.EVENTS.AUCTION_END, BID_RESPONSE_MOCK);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK);
- const responses = analyticsAdapter.context.auctionObject.bidResponses;
- expect(responses.length).to.be.eql(2);
- expect(responses[0].total_duration).to.be.eql(null);
- expect(responses[1].total_duration).to.be.eql(null);
+ const impressions = analyticsAdapter.context.auctionObject.impressions;
+ expect(impressions.length).to.be.eql(3);
});
it('Firing BID_WON should set to 1 the status of the corresponding bid', () => {
@@ -180,8 +176,6 @@ describe('RIVR Analytics adapter', () => {
expect(analyticsAdapter.context.auctionObject.bidders.length).to.be.equal(3);
- console.log('analyticsAdapter.context.auctionObject.bidders[0]', analyticsAdapter.context.auctionObject.bidders[0]);
-
expect(analyticsAdapter.context.auctionObject.bidders[0].bids[0].status).to.be.equal(0);
expect(analyticsAdapter.context.auctionObject.bidders[1].bids[0].status).to.be.equal(0);
@@ -190,18 +184,6 @@ describe('RIVR Analytics adapter', () => {
expect(analyticsAdapter.context.auctionObject.bidders[2].bids[1].status).to.be.equal(0);
});
- it('Firing BID_WON when it happens after BID_RESPONSE should change the status of winning bidResponse to 1', () => {
- const BID_STATUS_WON = 1;
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
-
- events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
- events.emit(CONSTANTS.EVENTS.BID_WON, BID_RESPONSE_MOCK);
-
- const responseWhichIsWonAlso = analyticsAdapter.context.auctionObject.bidResponses[0];
-
- expect(responseWhichIsWonAlso.seatbid[0].bid[0].status).to.be.eql(BID_STATUS_WON);
- });
-
it('when auction is initialized and authToken is defined and ExpiringQueue ttl expires, it sends the auction', () => {
events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000});
analyticsAdapter.context.authToken = 'anAuthToken';
@@ -213,31 +195,23 @@ describe('RIVR Analytics adapter', () => {
expect(ajaxStub.calledOnce).to.be.equal(true);
});
- it('when auction is initialized and authToken is defined and ExpiringQueue ttl expires, it clears imp, bidResponses and bidRequests', () => {
+ it('when auction is initialized and authToken is defined and ExpiringQueue ttl expires, it resets auctionObject', () => {
events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000});
analyticsAdapter.context.authToken = 'anAuthToken';
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
- events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
- events.emit(CONSTANTS.EVENTS.BID_WON, BID_RESPONSE_MOCK);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK);
- let impressions = analyticsAdapter.context.auctionObject.imp;
- let responses = analyticsAdapter.context.auctionObject.bidResponses;
- let requests = analyticsAdapter.context.auctionObject.bidRequests;
+ let impressions = analyticsAdapter.context.auctionObject.impressions;
- expect(impressions.length).to.be.eql(1);
- expect(responses.length).to.be.eql(1);
- expect(requests.length).to.be.eql(1);
+ expect(impressions.length).to.be.eql(3);
timer.tick(EXPIRING_QUEUE_TIMEOUT + 500);
- let impressionsAfterSend = analyticsAdapter.context.auctionObject.imp;
- let responsesAfterSend = analyticsAdapter.context.auctionObject.bidResponses;
- let requestsAfterSend = analyticsAdapter.context.auctionObject.bidRequests;
+ let impressionsAfterSend = analyticsAdapter.context.auctionObject.impressions;
+ let biddersAfterSend = analyticsAdapter.context.auctionObject.bidders;
expect(impressionsAfterSend.length).to.be.eql(0);
- expect(responsesAfterSend.length).to.be.eql(0);
- expect(requestsAfterSend.length).to.be.eql(0);
+ expect(biddersAfterSend.length).to.be.eql(0);
});
it('sendAuction(), when authToken is defined, it fires call clearing empty payload properties', () => {
From cdbd41306aea490e98b6781549310006b0d55cf0 Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 2 Nov 2018 13:47:14 +0100
Subject: [PATCH 59/62] RVR-2005 - Add Rivr Analytics adapter md file
---
modules/rivrAnalyticsAdapter.md | 13 +++++++++++++
1 file changed, 13 insertions(+)
create mode 100644 modules/rivrAnalyticsAdapter.md
diff --git a/modules/rivrAnalyticsAdapter.md b/modules/rivrAnalyticsAdapter.md
new file mode 100644
index 00000000000..787034e362e
--- /dev/null
+++ b/modules/rivrAnalyticsAdapter.md
@@ -0,0 +1,13 @@
+# Overview
+
+Module Name: Rivr Analytics Adapter
+
+Module Type: Analytics Adapter
+
+Maintainer: rnd@simplaex.com
+
+# Description
+
+Analytics adapter for www.rivr.ai.
+
+Contact support@simplaex.com for information and support.
From f38fb3bbde7e28e1ca5f32d7590d596d53561212 Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 2 Nov 2018 13:57:00 +0100
Subject: [PATCH 60/62] RVR-2005 - rewrite connectAllUnits
---
modules/rivrAnalyticsAdapter.js | 9 +++------
test/spec/modules/rivrAnalyticsAdapter_spec.js | 6 +++---
2 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index 8fdf817a37d..c99c81d7f76 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -326,7 +326,7 @@ export function saveUnoptimisedAdUnits() {
let units = rivrAnalytics.context.adUnits;
if (units) {
if (units.length > 0) {
- let allUnits = connectAllUnits(units);
+ let allUnits = concatAllUnits(units);
allUnits.forEach((adUnit) => {
adUnit.bids.forEach((bid) => {
let configForBidder = fetchConfigForBidder(bid.bidder);
@@ -340,11 +340,8 @@ export function saveUnoptimisedAdUnits() {
}
};
-export function connectAllUnits(units) {
- return units.reduce((acc, units) => {
- units.forEach((unit) => acc.push(unit))
- return acc
- }, []);
+export function concatAllUnits(units) {
+ return Array.prototype.concat.apply([], units);
}
export function createUnOptimisedParamsField(bid, config) {
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 63ef6176870..770fc3709a3 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -10,7 +10,7 @@ import {
pinHandlerToHTMLElement,
setAuctionAbjectPosition,
createNewAuctionObject,
- connectAllUnits,
+ concatAllUnits,
trackAuctionEnd,
} from 'modules/rivrAnalyticsAdapter';
import {expect} from 'chai';
@@ -465,10 +465,10 @@ describe('RIVR Analytics adapter', () => {
expect(result.site.categories).to.be.equal(SITE_CATEGORIES_MOCK);
});
- it('connectAllUnits(), returns a flattened array with all banner and video adunits', () => {
+ it('concatAllUnits(), returns a flattened array with all banner and video adunits', () => {
const allAdUnits = [BANNER_AD_UNITS_MOCK, VIDEO_AD_UNITS_MOCK];
- const result = connectAllUnits(allAdUnits);
+ const result = concatAllUnits(allAdUnits);
expect(result.length).to.be.eql(2);
expect(result[0].code).to.be.eql('banner-container1');
From 41430e611aac85ffd00309f897b9b98d273c9466 Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 2 Nov 2018 14:14:57 +0100
Subject: [PATCH 61/62] RVR-2005 - correct typo
---
test/spec/modules/rivrAnalyticsAdapter_spec.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index 770fc3709a3..0fc20171e0a 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -160,7 +160,7 @@ describe('RIVR Analytics adapter', () => {
expect(endTime).to.be.eql(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
});
- it('Firing AUCTION_END populates impressions arrai in auction object', () => {
+ it('Firing AUCTION_END populates impressions array in auction object', () => {
analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
events.emit(CONSTANTS.EVENTS.AUCTION_END, AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK);
From 88d81213ea1667d94d5ecc6973f18fe158a7d010 Mon Sep 17 00:00:00 2001
From: adg
Date: Fri, 2 Nov 2018 14:20:02 +0100
Subject: [PATCH 62/62] RVR-2005 - use IE compatible find()
---
modules/rivrAnalyticsAdapter.js | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index c99c81d7f76..14143f5f21d 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -1,5 +1,6 @@
import {ajax} from 'src/ajax';
import adapter from 'src/AnalyticsAdapter';
+import find from 'core-js/library/fn/array/find';
import CONSTANTS from 'src/constants.json';
import adaptermanager from 'src/adaptermanager';
import { logInfo, generateUUID, timestamp } from 'src/utils';
@@ -98,11 +99,11 @@ function trackBidWon(args) {
function setWinningBidStatus(args) {
let auctionObject = rivrAnalytics.context.auctionObject;
- const bidderObjectForThisWonBid = auctionObject.bidders.find((bidder) => {
+ const bidderObjectForThisWonBid = find(auctionObject.bidders, (bidder) => {
return bidder.id === args.bidderCode;
});
if (bidderObjectForThisWonBid) {
- const bidObjectForThisWonBid = bidderObjectForThisWonBid.bids.find((bid) => {
+ const bidObjectForThisWonBid = find(bidderObjectForThisWonBid.bids, (bid) => {
return bid.impId === args.adUnitCode;
});
if (bidObjectForThisWonBid) {
@@ -123,7 +124,7 @@ function buildImpressionsArrayFromAuctionEnd(auctionEndEvent) {
impression.id = adUnit.code;
impression.adType = 'unknown';
impression.acceptedSizes = [];
- const bidReceivedForThisAdUnit = auctionEndEvent.bidsReceived.find((bidReceived) => {
+ const bidReceivedForThisAdUnit = find(auctionEndEvent.bidsReceived, (bidReceived) => {
return adUnit.code === bidReceived.adUnitCode;
});
if (adUnit.mediaTypes) {
@@ -158,7 +159,7 @@ function buildBiddersArrayFromAuctionEnd(auctionEndEvent) {
const bidder = {};
bidder.id = bidderRequest.bidderCode;
bidder.bids = bidderRequest.bids.map((bid) => {
- const bidReceivedForThisRequest = auctionEndEvent.bidsReceived.find((bidReceived) => {
+ const bidReceivedForThisRequest = find(auctionEndEvent.bidsReceived, (bidReceived) => {
return bidderRequest.bidderCode === bidReceived.bidderCode &&
bid.bidId === bidReceived.adId &&
bid.adUnitCode === bidReceived.adUnitCode;